@ohif/app 3.8.0-beta.62 → 3.8.0-beta.64

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 (32) hide show
  1. package/dist/{121.bundle.ed23e7752a11005322e6.js → 121.bundle.5399d807995157d368b7.js} +4 -4
  2. package/dist/{155.bundle.19e63774cdf16306b5b6.js → 155.bundle.55fa02bfc411cc91e261.js} +12 -7
  3. package/dist/{188.bundle.7e085b90e138357e6789.js → 188.bundle.ec979013d89d90831c58.js} +2 -2
  4. package/dist/{270.bundle.36c4e95efb89ad8bd8ae.js → 270.bundle.58c74e58ad67b5069718.js} +51 -28
  5. package/dist/{295.bundle.462f3328c716cbe6c613.js → 295.bundle.c0a29ff64d86f707fc20.js} +4 -4
  6. package/dist/{339.bundle.2271a993c53d0728c816.js → 339.bundle.e31c81c7179d3d24f3dd.js} +27 -69
  7. package/dist/{68.bundle.0420d25b4736f20b15b2.js → 41.bundle.0696b28613c7d47833c9.js} +276 -486
  8. package/dist/{250.bundle.a064577944a0691bc77d.js → 448.bundle.e856d2b2bd979c7d9ac0.js} +238 -382
  9. package/dist/{530.bundle.ce13c30b93a28cc85098.js → 530.bundle.f00fd953dcd9d0afd10b.js} +2 -2
  10. package/dist/{544.bundle.3cf20da53f349abd8d67.js → 544.bundle.adfe5764f59b5fe0eba7.js} +5 -17
  11. package/dist/{559.bundle.42a8edafa1c7df761194.js → 559.bundle.4f55f5df04c418b2854e.js} +6 -10
  12. package/dist/{594.bundle.6667c5cc14b924d7bee6.js → 594.bundle.924cdc10e7435cf3e199.js} +147 -188
  13. package/dist/{50.bundle.a18826e121bdd0c2a707.js → 638.bundle.62f8f8ada74bd900abfc.js} +158 -394
  14. package/dist/{317.bundle.7ef949a52571bc04e7e1.js → 699.bundle.b3b25017819be681ef3d.js} +323 -186
  15. package/dist/{963.bundle.3daa5c08231526d905fb.js → 701.bundle.b7ebc1629fc121e13c58.js} +520 -210
  16. package/dist/{724.bundle.941cd2a3b43a84d5893f.js → 724.bundle.cd011bc1838a2bde1d66.js} +89 -152
  17. package/dist/{862.bundle.e3fe2aae7903cc2ae8df.js → 862.bundle.d2e78b70286b59569e83.js} +2 -2
  18. package/dist/{889.bundle.6850a0b8c412e3befab5.js → 889.bundle.2aefa0a3eb114db0de3f.js} +180 -207
  19. package/dist/{704.bundle.242ba4e0b0be7d1fec94.js → 90.bundle.7a9258532111121b5ee3.js} +228 -338
  20. package/dist/{905.bundle.eb7bdaec4276399e5bef.js → 905.bundle.d4bdcbd451de59b2191b.js} +119 -89
  21. package/dist/{907.bundle.fc8115500a085ab2bbec.js → 907.bundle.ca236b83967a8459b778.js} +2 -14
  22. package/dist/{961.bundle.f5d9e73fa771ce7e73f3.js → 961.bundle.a5541d8090cb8b22f7e6.js} +2 -15
  23. package/dist/{987.bundle.e7c041a6dfb4ddb41813.js → 987.bundle.91d4867efedd5b4d84cb.js} +5 -1
  24. package/dist/{app.bundle.a78a51e39321426c5460.js → app.bundle.039c4dc99821370f330d.js} +1991 -931
  25. package/dist/app.bundle.css +1 -1
  26. package/dist/index.html +1 -1
  27. package/dist/{polySeg.bundle.99be036bab9b7f011b0c.js → polySeg.bundle.c1cec6312eb6c6dc3701.js} +1 -1
  28. package/dist/sw.js +1 -1
  29. package/package.json +17 -17
  30. /package/dist/{164.bundle.0b17fced9916487eb49f.js → 164.bundle.0cfa2edabf8ef222f3ea.js} +0 -0
  31. /package/dist/{50.css → 638.css} +0 -0
  32. /package/dist/{963.css → 701.css} +0 -0
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
- (globalThis["webpackChunk"] = globalThis["webpackChunk"] || []).push([[704],{
2
+ (globalThis["webpackChunk"] = globalThis["webpackChunk"] || []).push([[90],{
3
3
 
4
- /***/ 49704:
4
+ /***/ 54090:
5
5
  /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
6
6
 
7
7
  // ESM COMPAT FLAG
@@ -31,8 +31,8 @@ __webpack_require__.d(utils_namespaceObject, {
31
31
 
32
32
  // EXTERNAL MODULE: ../../../node_modules/dicomweb-client/build/dicomweb-client.es.js
33
33
  var dicomweb_client_es = __webpack_require__(36922);
34
- // EXTERNAL MODULE: ../../core/src/index.ts + 66 modules
35
- var src = __webpack_require__(14283);
34
+ // EXTERNAL MODULE: ../../core/src/index.ts + 67 modules
35
+ var src = __webpack_require__(78198);
36
36
  // EXTERNAL MODULE: ../../core/src/utils/sortStudy.ts
37
37
  var sortStudy = __webpack_require__(45476);
38
38
  ;// CONCATENATED MODULE: ../../../extensions/default/src/DicomWebDataSource/qido.js
@@ -2484,8 +2484,8 @@ var react = __webpack_require__(41766);
2484
2484
  // EXTERNAL MODULE: ../../../node_modules/prop-types/index.js
2485
2485
  var prop_types = __webpack_require__(11374);
2486
2486
  var prop_types_default = /*#__PURE__*/__webpack_require__.n(prop_types);
2487
- // EXTERNAL MODULE: ../../ui/src/index.js + 487 modules
2488
- var ui_src = __webpack_require__(55395);
2487
+ // EXTERNAL MODULE: ../../ui/src/index.js + 495 modules
2488
+ var ui_src = __webpack_require__(65967);
2489
2489
  // EXTERNAL MODULE: ./state/index.js + 1 modules
2490
2490
  var state = __webpack_require__(15575);
2491
2491
  // EXTERNAL MODULE: ../node_modules/react-router-dom/dist/index.js
@@ -2504,48 +2504,49 @@ function _extends() { _extends = Object.assign ? Object.assign.bind() : function
2504
2504
 
2505
2505
 
2506
2506
 
2507
+
2507
2508
  function Toolbar({
2508
2509
  servicesManager
2509
2510
  }) {
2510
2511
  const {
2511
- toolbarService
2512
- } = servicesManager.services;
2513
- const [viewportGrid, viewportGridService] = (0,ui_src/* useViewportGrid */.ih)();
2514
- const [toolbarButtons, setToolbarButtons] = (0,react.useState)([]);
2515
- (0,react.useEffect)(() => {
2516
- const updateToolbar = () => {
2517
- const toolGroupId = viewportGridService.getActiveViewportOptionByKey('toolGroupId') ?? 'default';
2518
- setToolbarButtons(toolbarService.getButtonSection(toolGroupId));
2519
- };
2520
- const {
2521
- unsubscribe
2522
- } = toolbarService.subscribe(toolbarService.EVENTS.TOOL_BAR_MODIFIED, updateToolbar);
2523
- updateToolbar();
2524
- return () => {
2525
- unsubscribe();
2526
- };
2527
- }, [toolbarService, viewportGrid]);
2528
- const onInteraction = (0,react.useCallback)(args => toolbarService.recordInteraction(args), [toolbarService]);
2512
+ toolbarButtons,
2513
+ onInteraction
2514
+ } = (0,src/* useToolbar */.tR)({
2515
+ servicesManager,
2516
+ buttonSection: 'primary'
2517
+ });
2518
+ if (!toolbarButtons.length) {
2519
+ return null;
2520
+ }
2529
2521
  return /*#__PURE__*/react.createElement(react.Fragment, null, toolbarButtons.map(toolDef => {
2522
+ if (!toolDef) {
2523
+ return null;
2524
+ }
2530
2525
  const {
2531
2526
  id,
2532
2527
  Component,
2533
2528
  componentProps
2534
2529
  } = toolDef;
2535
- return (
2536
- /*#__PURE__*/
2537
- // The margin for separating the tools on the toolbar should go here and NOT in each individual component (button) item.
2538
- // This allows for the individual items to be included in other UI components where perhaps alternative margins are desired.
2539
- react.createElement("div", {
2540
- key: id,
2541
- className: classnames_default()('mr-1')
2542
- }, /*#__PURE__*/react.createElement(Component, _extends({
2543
- id: id
2544
- }, componentProps, {
2545
- onInteraction: onInteraction,
2546
- servicesManager: servicesManager
2547
- })))
2548
- );
2530
+ const {
2531
+ disabled
2532
+ } = componentProps;
2533
+ const tool = /*#__PURE__*/react.createElement(Component, _extends({
2534
+ key: id,
2535
+ id: id,
2536
+ onInteraction: onInteraction,
2537
+ servicesManager: servicesManager
2538
+ }, componentProps));
2539
+ return disabled ? /*#__PURE__*/react.createElement(ui_src/* Tooltip */.m_, {
2540
+ key: id,
2541
+ position: "bottom",
2542
+ content: componentProps.label,
2543
+ secondaryContent: 'Not available on the current viewport'
2544
+ }, /*#__PURE__*/react.createElement("div", {
2545
+ className: classnames_default()('mr-1')
2546
+ }, tool)) : /*#__PURE__*/react.createElement("div", {
2547
+ key: id,
2548
+ className: "mr-1"
2549
+ }, tool);
2549
2550
  }));
2550
2551
  }
2551
2552
  ;// CONCATENATED MODULE: ../../../extensions/default/src/ViewerLayout/ViewerHeader.tsx
@@ -2603,8 +2604,8 @@ function ViewerHeader({
2603
2604
  hotkeyDefinitions,
2604
2605
  hotkeyDefaults
2605
2606
  } = hotkeysManager;
2606
- const versionNumber = "3.8.0-beta.62";
2607
- const commitHash = "9bcd1ae6f51d61786cc1e99624f396b56a47cd69";
2607
+ const versionNumber = "3.8.0-beta.64";
2608
+ const commitHash = "566b25a54425399096864bd263193646556011a5";
2608
2609
  const menuOptions = [{
2609
2610
  title: t('Header:About'),
2610
2611
  icon: 'info',
@@ -2758,18 +2759,12 @@ function ViewerLayout({
2758
2759
  }, []);
2759
2760
  const getComponent = id => {
2760
2761
  const entry = extensionManager.getModuleEntry(id);
2761
- if (!entry) {
2762
- throw new Error(`${id} is not valid for an extension module. Please verify your configuration or ensure that the extension is properly registered. It's also possible that your mode is utilizing a module from an extension that hasn't been included in its dependencies (add the extension to the "extensionDependencies" array in your mode's index.js file)`);
2763
- }
2764
- let content;
2765
- if (entry && entry.component) {
2766
- content = entry.component;
2767
- } else {
2768
- throw new Error(`No component found from extension ${id}. Check the reference string to the extension in your Mode configuration`);
2762
+ if (!entry || !entry.component) {
2763
+ throw new Error(`${id} is not valid for an extension module or no component found from extension ${id}. Please verify your configuration or ensure that the extension is properly registered. It's also possible that your mode is utilizing a module from an extension that hasn't been included in its dependencies (add the extension to the "extensionDependencies" array in your mode's index.js file). Check the reference string to the extension in your Mode configuration`);
2769
2764
  }
2770
2765
  return {
2771
2766
  entry,
2772
- content
2767
+ content: entry.component
2773
2768
  };
2774
2769
  };
2775
2770
  const getPanelData = id => {
@@ -2783,7 +2778,8 @@ function ViewerLayout({
2783
2778
  iconLabel: entry.iconLabel,
2784
2779
  label: entry.label,
2785
2780
  name: entry.name,
2786
- content
2781
+ content,
2782
+ contexts: entry.contexts
2787
2783
  };
2788
2784
  };
2789
2785
  (0,react.useEffect)(() => {
@@ -2847,7 +2843,9 @@ function ViewerLayout({
2847
2843
  activeTabIndex: rightPanelDefaultClosed ? null : 0,
2848
2844
  tabs: rightPanelComponents,
2849
2845
  servicesManager: servicesManager
2850
- })) : null)));
2846
+ })) : null)), /*#__PURE__*/react.createElement(ui_src/* InvestigationalUseDialog */.j, {
2847
+ dialogConfiguration: appConfig?.investigationalUseDialog
2848
+ }));
2851
2849
  }
2852
2850
  ViewerLayout.propTypes = {
2853
2851
  // From extension module params
@@ -3238,6 +3236,11 @@ function _createStudyBrowserTabs(primaryStudyInstanceUIDs, studyDisplayList, dis
3238
3236
  function getImageSrcFromImageId(cornerstone, imageId) {
3239
3237
  return new Promise((resolve, reject) => {
3240
3238
  const canvas = document.createElement('canvas');
3239
+ // Note: the default width and height of the canvas is 300x150
3240
+ // but we need to set the width and height to the same number since
3241
+ // the thumbnails are usually square and we want to maintain the aspect ratio
3242
+ canvas.width = 128 / window.devicePixelRatio;
3243
+ canvas.height = 128 / window.devicePixelRatio;
3241
3244
  cornerstone.utilities.loadImageToCanvas({
3242
3245
  canvas,
3243
3246
  imageId
@@ -4451,32 +4454,37 @@ function ToolbarLayoutSelector_extends() { ToolbarLayoutSelector_extends = Objec
4451
4454
 
4452
4455
  function ToolbarLayoutSelectorWithServices({
4453
4456
  servicesManager,
4457
+ commands,
4454
4458
  ...props
4455
4459
  }) {
4456
4460
  const {
4457
- toolbarService
4461
+ toolbarService,
4462
+ viewportGridService
4458
4463
  } = servicesManager.services;
4459
- const onSelection = (0,react.useCallback)(props => {
4464
+ const onInteraction = (0,react.useCallback)(args => {
4465
+ const viewportId = viewportGridService.getActiveViewportId();
4466
+ const refreshProps = {
4467
+ viewportId
4468
+ };
4469
+ if (props.onLayoutChange) {
4470
+ props.onLayoutChange(args);
4471
+ }
4460
4472
  toolbarService.recordInteraction({
4461
- interactionType: 'action',
4462
- commands: [{
4463
- commandName: 'setViewportGridLayout',
4464
- commandOptions: {
4465
- ...props
4466
- },
4467
- context: 'DEFAULT'
4468
- }]
4473
+ commands
4474
+ }, {
4475
+ ...args,
4476
+ refreshProps
4469
4477
  });
4470
4478
  }, [toolbarService]);
4471
4479
  return /*#__PURE__*/react.createElement(LayoutSelector, ToolbarLayoutSelector_extends({}, props, {
4472
- onSelection: onSelection
4480
+ onInteraction: onInteraction
4473
4481
  }));
4474
4482
  }
4475
4483
  function LayoutSelector({
4476
4484
  rows,
4477
4485
  columns,
4478
4486
  className,
4479
- onSelection,
4487
+ onInteraction,
4480
4488
  ...rest
4481
4489
  }) {
4482
4490
  const [isOpen, setIsOpen] = (0,react.useState)(false);
@@ -4503,7 +4511,7 @@ function LayoutSelector({
4503
4511
  dropdownContent: DropdownContent !== null && /*#__PURE__*/react.createElement(DropdownContent, {
4504
4512
  rows: rows,
4505
4513
  columns: columns,
4506
- onSelection: onSelection
4514
+ onSelection: onInteraction
4507
4515
  }),
4508
4516
  isActive: isOpen,
4509
4517
  type: "toggle"
@@ -4526,10 +4534,7 @@ function ToolbarSplitButtonWithServices_extends() { ToolbarSplitButtonWithServic
4526
4534
 
4527
4535
 
4528
4536
 
4529
-
4530
4537
  function ToolbarSplitButtonWithServices({
4531
- isRadio,
4532
- isAction,
4533
4538
  groupId,
4534
4539
  primary,
4535
4540
  secondary,
@@ -4541,105 +4546,27 @@ function ToolbarSplitButtonWithServices({
4541
4546
  const {
4542
4547
  toolbarService
4543
4548
  } = servicesManager?.services;
4544
- const handleItemClick = (item, index) => {
4545
- const {
4546
- id,
4547
- type,
4548
- commands
4549
- } = item;
4550
- onInteraction({
4551
- groupId,
4552
- itemId: id,
4553
- interactionType: type,
4554
- commands
4555
- });
4556
- setState(state => ({
4557
- ...state,
4558
- primary: !isAction && isRadio ? {
4559
- ...item,
4560
- index
4561
- } : state.primary,
4562
- isExpanded: false,
4563
- items: getSplitButtonItems(items).filter(item => isRadio && !isAction ? item.index !== index : true)
4564
- }));
4565
- };
4566
4549
 
4567
4550
  /* Bubbles up individual item clicks */
4568
- const getSplitButtonItems = items => items.map((item, index) => ({
4551
+ const getSplitButtonItems = (0,react.useCallback)(items => items.map((item, index) => ({
4569
4552
  ...item,
4570
4553
  index,
4571
- onClick: () => handleItemClick(item, index)
4572
- }));
4573
- const [buttonsState, setButtonState] = (0,react.useState)({
4574
- primaryToolId: '',
4575
- toggles: {},
4576
- groups: {}
4577
- });
4578
- const [state, setState] = (0,react.useState)({
4579
- primary,
4580
- items: getSplitButtonItems(items).filter(item => isRadio && !isAction ? item.id !== primary.id : true)
4581
- });
4582
- const {
4583
- primaryToolId,
4584
- toggles
4585
- } = buttonsState;
4586
- const isPrimaryToggle = state.primary.type === 'toggle';
4587
- const isPrimaryActive = state.primary.type === 'tool' && primaryToolId === state.primary.id || isPrimaryToggle && toggles[state.primary.id] === true;
4588
- const PrimaryButtonComponent = toolbarService?.getButtonComponentForUIType(state.primary.uiType) ?? ui_src/* ToolbarButton */.IB;
4589
- (0,react.useEffect)(() => {
4590
- const {
4591
- unsubscribe
4592
- } = toolbarService.subscribe(toolbarService.EVENTS.TOOL_BAR_STATE_MODIFIED, state => {
4593
- setButtonState({
4594
- ...state
4554
+ onClick: () => {
4555
+ onInteraction({
4556
+ groupId,
4557
+ itemId: item.id,
4558
+ commands: item.commands
4595
4559
  });
4596
- });
4597
- return () => {
4598
- unsubscribe();
4599
- };
4600
- }, [toolbarService]);
4601
- const updatedItems = state.items.map(item => {
4602
- const isActive = item.type === 'tool' && primaryToolId === item.id;
4603
-
4604
- // We could have added the
4605
- // item.type === 'toggle' && toggles[item.id] === true
4606
- // too but that makes the button active when the toggle is active under it
4607
- // which feels weird
4608
- return {
4609
- ...item,
4610
- isActive
4611
- };
4612
- });
4613
- const DefaultListItemRenderer = ({
4614
- type,
4615
- icon,
4616
- label,
4617
- t,
4618
- id
4619
- }) => {
4620
- const isActive = type === 'toggle' && toggles[id] === true;
4621
- return /*#__PURE__*/react.createElement("div", {
4622
- className: classnames_default()('hover:bg-primary-dark flex h-8 w-full flex-row items-center p-3', 'whitespace-pre text-base', isActive && 'bg-primary-dark', isActive ? 'text-[#348CFD]' : 'text-common-bright hover:bg-primary-dark hover:text-primary-light')
4623
- }, icon && /*#__PURE__*/react.createElement("span", {
4624
- className: "mr-4"
4625
- }, /*#__PURE__*/react.createElement(ui_src/* Icon */.In, {
4626
- name: icon,
4627
- className: "h-5 w-5"
4628
- })), /*#__PURE__*/react.createElement("span", {
4629
- className: "mr-5"
4630
- }, t(label)));
4631
- };
4632
- const listItemRenderer = renderer || DefaultListItemRenderer;
4560
+ }
4561
+ })), []);
4562
+ const PrimaryButtonComponent = toolbarService?.getButtonComponentForUIType(primary.uiType) ?? ui_src/* ToolbarButton */.IB;
4563
+ const listItemRenderer = renderer;
4633
4564
  return /*#__PURE__*/react.createElement(ui_src/* SplitButton */.fk, {
4634
- isRadio: isRadio,
4635
- isAction: isAction,
4636
- primary: state.primary,
4565
+ primary: primary,
4637
4566
  secondary: secondary,
4638
- items: updatedItems,
4567
+ items: getSplitButtonItems(items),
4639
4568
  groupId: groupId,
4640
4569
  renderer: listItemRenderer,
4641
- isActive: isPrimaryActive || updatedItems.some(item => item.isActive),
4642
- isToggle: isPrimaryToggle,
4643
4570
  onInteraction: onInteraction,
4644
4571
  Component: props => /*#__PURE__*/react.createElement(PrimaryButtonComponent, ToolbarSplitButtonWithServices_extends({}, props, {
4645
4572
  servicesManager: servicesManager
@@ -4648,11 +4575,9 @@ function ToolbarSplitButtonWithServices({
4648
4575
  }
4649
4576
  ToolbarSplitButtonWithServices.propTypes = {
4650
4577
  isRadio: (prop_types_default()).bool,
4651
- isAction: (prop_types_default()).bool,
4652
4578
  groupId: (prop_types_default()).string,
4653
4579
  primary: prop_types_default().shape({
4654
4580
  id: (prop_types_default()).string.isRequired,
4655
- type: prop_types_default().oneOf(['tool', 'action', 'toggle']).isRequired,
4656
4581
  uiType: (prop_types_default()).string
4657
4582
  }),
4658
4583
  secondary: prop_types_default().shape({
@@ -4660,14 +4585,16 @@ ToolbarSplitButtonWithServices.propTypes = {
4660
4585
  icon: (prop_types_default()).string.isRequired,
4661
4586
  label: (prop_types_default()).string,
4662
4587
  tooltip: (prop_types_default()).string.isRequired,
4663
- isActive: (prop_types_default()).bool
4588
+ disabled: (prop_types_default()).bool,
4589
+ className: (prop_types_default()).string
4664
4590
  }),
4665
4591
  items: prop_types_default().arrayOf(prop_types_default().shape({
4666
4592
  id: (prop_types_default()).string.isRequired,
4667
- type: prop_types_default().oneOf(['tool', 'action', 'toggle']).isRequired,
4668
4593
  icon: (prop_types_default()).string,
4669
4594
  label: (prop_types_default()).string,
4670
- tooltip: (prop_types_default()).string
4595
+ tooltip: (prop_types_default()).string,
4596
+ disabled: (prop_types_default()).bool,
4597
+ className: (prop_types_default()).string
4671
4598
  })),
4672
4599
  renderer: (prop_types_default()).func,
4673
4600
  onInteraction: (prop_types_default()).func.isRequired,
@@ -4682,106 +4609,102 @@ ToolbarSplitButtonWithServices.defaultProps = {
4682
4609
  isAction: false
4683
4610
  };
4684
4611
  /* harmony default export */ const Toolbar_ToolbarSplitButtonWithServices = (ToolbarSplitButtonWithServices);
4685
- ;// CONCATENATED MODULE: ../../../extensions/default/src/Toolbar/ToolbarButtonWithServices.tsx
4686
- function ToolbarButtonWithServices_extends() { ToolbarButtonWithServices_extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return ToolbarButtonWithServices_extends.apply(this, arguments); }
4687
-
4612
+ ;// CONCATENATED MODULE: ../../../extensions/default/src/Toolbar/ToolbarButtonGroupWithServices.tsx
4688
4613
 
4689
4614
 
4690
- function ToolbarButtonWithServices({
4691
- id,
4692
- type,
4693
- commands,
4615
+ function ToolbarButtonGroupWithServices({
4616
+ groupId,
4617
+ items,
4694
4618
  onInteraction,
4695
- servicesManager,
4696
- ...props
4619
+ size
4697
4620
  }) {
4698
- const {
4699
- toolbarService
4700
- } = servicesManager?.services || {};
4701
- const [buttonsState, setButtonState] = (0,react.useState)({
4702
- primaryToolId: '',
4703
- toggles: {},
4704
- groups: {}
4705
- });
4706
- const {
4707
- primaryToolId
4708
- } = buttonsState;
4709
- const isActive = type === 'tool' && id === primaryToolId || type === 'toggle' && buttonsState.toggles[id] === true;
4710
- (0,react.useEffect)(() => {
4711
- const {
4712
- unsubscribe
4713
- } = toolbarService.subscribe(toolbarService.EVENTS.TOOL_BAR_STATE_MODIFIED, state => {
4714
- setButtonState({
4715
- ...state
4621
+ const getSplitButtonItems = (0,react.useCallback)(items => items.map((item, index) => /*#__PURE__*/react.createElement(ui_src/* ToolbarButton */.IB, {
4622
+ key: item.id,
4623
+ icon: item.icon,
4624
+ label: item.label,
4625
+ disabled: item.disabled,
4626
+ className: item.className,
4627
+ id: item.id,
4628
+ size: size,
4629
+ onClick: () => {
4630
+ onInteraction({
4631
+ groupId,
4632
+ itemId: item.id,
4633
+ commands: item.commands
4716
4634
  });
4717
- });
4718
- return () => {
4719
- unsubscribe();
4720
- };
4721
- }, [toolbarService]);
4722
- return /*#__PURE__*/react.createElement(ui_src/* ToolbarButton */.IB, ToolbarButtonWithServices_extends({
4723
- commands: commands,
4724
- id: id,
4725
- type: type,
4726
- isActive: isActive,
4727
- onInteraction: onInteraction
4728
- }, props));
4635
+ }
4636
+ // Note: this is necessary since tooltip will add
4637
+ // default styles to the tooltip container which
4638
+ // we don't want for groups
4639
+ ,
4640
+ toolTipClassName: ""
4641
+ })), [onInteraction, groupId]);
4642
+ return /*#__PURE__*/react.createElement(ui_src/* ButtonGroup */.e2, null, getSplitButtonItems(items));
4729
4643
  }
4730
- ToolbarButtonWithServices.propTypes = {
4731
- id: (prop_types_default()).string.isRequired,
4732
- type: prop_types_default().oneOf(['tool', 'action', 'toggle']).isRequired,
4733
- commands: prop_types_default().arrayOf(prop_types_default().shape({
4734
- commandName: (prop_types_default()).string.isRequired,
4735
- context: (prop_types_default()).string
4736
- })),
4737
- onInteraction: (prop_types_default()).func.isRequired,
4738
- servicesManager: prop_types_default().shape({
4739
- services: prop_types_default().shape({
4740
- toolbarService: prop_types_default().shape({
4741
- subscribe: (prop_types_default()).func.isRequired,
4742
- state: prop_types_default().shape({
4743
- primaryToolId: (prop_types_default()).string,
4744
- toggles: prop_types_default().objectOf((prop_types_default()).bool),
4745
- groups: prop_types_default().objectOf((prop_types_default()).any)
4746
- }).isRequired
4747
- }).isRequired
4748
- }).isRequired
4749
- }).isRequired
4750
- };
4751
- /* harmony default export */ const Toolbar_ToolbarButtonWithServices = (ToolbarButtonWithServices);
4644
+ /* harmony default export */ const Toolbar_ToolbarButtonGroupWithServices = (ToolbarButtonGroupWithServices);
4752
4645
  ;// CONCATENATED MODULE: ../../../extensions/default/src/getToolbarModule.tsx
4753
4646
 
4754
4647
 
4755
4648
 
4756
4649
 
4650
+
4651
+ const getClassName = isToggled => {
4652
+ return {
4653
+ className: isToggled ? '!text-primary-active' : '!text-common-bright hover:!bg-primary-dark hover:text-primary-light'
4654
+ };
4655
+ };
4757
4656
  function getToolbarModule({
4758
4657
  commandsManager,
4759
4658
  servicesManager
4760
4659
  }) {
4660
+ const {
4661
+ cineService
4662
+ } = servicesManager.services;
4761
4663
  return [{
4762
- name: 'ohif.divider',
4763
- defaultComponent: ToolbarDivider,
4764
- clickHandler: () => {}
4765
- }, {
4766
- name: 'ohif.action',
4767
- defaultComponent: Toolbar_ToolbarButtonWithServices,
4768
- clickHandler: () => {}
4769
- }, {
4770
4664
  name: 'ohif.radioGroup',
4771
- defaultComponent: Toolbar_ToolbarButtonWithServices,
4772
- clickHandler: () => {}
4665
+ defaultComponent: ui_src/* ToolbarButton */.IB
4666
+ }, {
4667
+ name: 'ohif.divider',
4668
+ defaultComponent: ToolbarDivider
4773
4669
  }, {
4774
4670
  name: 'ohif.splitButton',
4775
- defaultComponent: Toolbar_ToolbarSplitButtonWithServices,
4776
- clickHandler: () => {}
4671
+ defaultComponent: Toolbar_ToolbarSplitButtonWithServices
4777
4672
  }, {
4778
4673
  name: 'ohif.layoutSelector',
4779
- defaultComponent: ToolbarLayoutSelector,
4780
- clickHandler: (evt, clickedBtn, btnSectionName) => {}
4674
+ defaultComponent: ToolbarLayoutSelector
4675
+ }, {
4676
+ name: 'ohif.buttonGroup',
4677
+ defaultComponent: Toolbar_ToolbarButtonGroupWithServices
4678
+ }, {
4679
+ name: 'evaluate.group.promoteToPrimary',
4680
+ evaluate: ({
4681
+ viewportId,
4682
+ button,
4683
+ itemId
4684
+ }) => {
4685
+ const {
4686
+ items
4687
+ } = button.props;
4688
+ if (!itemId) {
4689
+ return {
4690
+ primary: button.props.primary,
4691
+ items
4692
+ };
4693
+ }
4694
+
4695
+ // other wise we can move the clicked tool to the primary button
4696
+ const clickedItemProps = items.find(item => item.id === itemId || item.itemId === itemId);
4697
+ return {
4698
+ primary: clickedItemProps,
4699
+ items
4700
+ };
4701
+ }
4781
4702
  }, {
4782
- name: 'ohif.toggle',
4783
- defaultComponent: Toolbar_ToolbarButtonWithServices,
4784
- clickHandler: () => {}
4703
+ name: 'evaluate.cine',
4704
+ evaluate: () => {
4705
+ const isToggled = cineService.getState().isCineEnabled;
4706
+ return getClassName(isToggled);
4707
+ }
4785
4708
  }];
4786
4709
  }
4787
4710
  ;// CONCATENATED MODULE: ../../../extensions/default/src/CustomizableContextMenu/ContextMenuItemsBuilder.ts
@@ -4847,7 +4770,6 @@ function findMenu(menus, props, menuIdFilter) {
4847
4770
  }
4848
4771
  current = findIt.next();
4849
4772
  }
4850
- console.log('Menu chosen', menu?.id || 'NONE');
4851
4773
  return menu;
4852
4774
  }
4853
4775
 
@@ -5012,7 +4934,6 @@ class ContextMenuController {
5012
4934
  console.warn('Annotation is locked.');
5013
4935
  return;
5014
4936
  }
5015
- console.log('Getting items from', menus);
5016
4937
  const items = getMenuItems(selectorProps || contextMenuProps, event, menus, menuId);
5017
4938
  this.services.uiDialogService.dismiss({
5018
4939
  id: 'context-menu'
@@ -5831,8 +5752,8 @@ const findViewportsByPosition = (state, {
5831
5752
  };
5832
5753
  };
5833
5754
  /* harmony default export */ const src_findViewportsByPosition = (findViewportsByPosition);
5834
- // EXTERNAL MODULE: ./index.js + 33 modules
5835
- var index = __webpack_require__(45573);
5755
+ // EXTERNAL MODULE: ./index.js + 35 modules
5756
+ var index = __webpack_require__(68870);
5836
5757
  ;// CONCATENATED MODULE: ../../../extensions/default/src/commandsModule.ts
5837
5758
 
5838
5759
 
@@ -5921,45 +5842,6 @@ const commandsModule = ({
5921
5842
  clearMeasurements: () => {
5922
5843
  measurementService.clear();
5923
5844
  },
5924
- /**
5925
- * Toggles off all tools which contain a commandName of setHangingProtocol
5926
- * or toggleHangingProtocol, and which match/don't match the protocol id/stage
5927
- */
5928
- toggleHpTools: () => {
5929
- const {
5930
- protocol,
5931
- stageIndex: toggleStageIndex,
5932
- stage
5933
- } = hangingProtocolService.getActiveProtocol();
5934
- const enableListener = button => {
5935
- if (!button.id) {
5936
- return;
5937
- }
5938
- const {
5939
- commands,
5940
- items,
5941
- primary
5942
- } = button.props || button;
5943
- if (primary) {
5944
- enableListener(primary);
5945
- }
5946
- if (items) {
5947
- items.forEach(enableListener);
5948
- }
5949
- const hpCommand = commands?.find?.(isHangingProtocolCommand);
5950
- if (!hpCommand) {
5951
- return;
5952
- }
5953
- const {
5954
- protocolId,
5955
- stageIndex,
5956
- stageId
5957
- } = hpCommand.commandOptions;
5958
- const isActive = (!protocolId || protocolId === protocol.id) && (stageIndex === undefined || stageIndex === toggleStageIndex) && (!stageId || stageId === stage.id);
5959
- toolbarService.setToggled(button.id, isActive);
5960
- };
5961
- Object.values(toolbarService.getButtons()).forEach(enableListener);
5962
- },
5963
5845
  /**
5964
5846
  * Sets the specified protocol
5965
5847
  * 1. Records any existing state using the viewport grid service
@@ -5991,16 +5873,12 @@ const commandsModule = ({
5991
5873
  stageIndex,
5992
5874
  reset = false
5993
5875
  }) => {
5994
- const primaryToolBeforeHPChange = toolbarService.getActivePrimaryTool();
5995
5876
  try {
5996
5877
  // Stores in the state the display set selector id to displaySetUID mapping
5997
5878
  // Pass in viewportId for the active viewport. This item will get set as
5998
5879
  // the activeViewportId
5999
5880
  const state = viewportGridService.getState();
6000
5881
  const hpInfo = hangingProtocolService.getState();
6001
- const {
6002
- protocol: oldProtocol
6003
- } = hangingProtocolService.getActiveProtocol();
6004
5882
  const stateSyncReduce = reuseCachedLayouts(state, hangingProtocolService, stateSyncService);
6005
5883
  const {
6006
5884
  hangingProtocolStageIndexMap,
@@ -6050,31 +5928,9 @@ const commandsModule = ({
6050
5928
  // multi-study display.
6051
5929
  delete displaySetSelectorMap[`${activeStudyUID || hpInfo.activeStudyUID}:activeDisplaySet:0`];
6052
5930
  stateSyncService.store(stateSyncReduce);
6053
- // This is a default action applied
6054
- actions.toggleHpTools();
6055
-
6056
- // try to use the same tool in the new hanging protocol stage
6057
- const primaryButton = toolbarService.getButton(primaryToolBeforeHPChange);
6058
- if (primaryButton) {
6059
- // is there any type of interaction on this button, if not it might be in the
6060
- // items. This is a bit of a hack, but it works for now.
6061
-
6062
- let interactionType = primaryButton.props?.interactionType;
6063
- if (!interactionType && primaryButton.props?.items) {
6064
- const firstItem = primaryButton.props.items[0];
6065
- interactionType = firstItem.props?.interactionType || firstItem.props?.type;
6066
- }
6067
- if (interactionType) {
6068
- toolbarService.recordInteraction({
6069
- interactionType,
6070
- ...primaryButton.props
6071
- });
6072
- }
6073
- }
6074
5931
  return true;
6075
5932
  } catch (e) {
6076
5933
  console.error(e);
6077
- actions.toggleHpTools();
6078
5934
  uiNotificationService.show({
6079
5935
  title: 'Apply Hanging Protocol',
6080
5936
  message: 'The hanging protocol could not be applied.',
@@ -6416,61 +6272,43 @@ const commandsModule = ({
6416
6272
  commandFn: actions.closeContextMenu
6417
6273
  },
6418
6274
  clearMeasurements: {
6419
- commandFn: actions.clearMeasurements,
6420
- storeContexts: [],
6421
- options: {}
6275
+ commandFn: actions.clearMeasurements
6422
6276
  },
6423
6277
  displayNotification: {
6424
- commandFn: actions.displayNotification,
6425
- storeContexts: [],
6426
- options: {}
6278
+ commandFn: actions.displayNotification
6427
6279
  },
6428
6280
  setHangingProtocol: {
6429
- commandFn: actions.setHangingProtocol,
6430
- storeContexts: [],
6431
- options: {}
6281
+ commandFn: actions.setHangingProtocol
6432
6282
  },
6433
6283
  toggleHangingProtocol: {
6434
- commandFn: actions.toggleHangingProtocol,
6435
- storeContexts: [],
6436
- options: {}
6284
+ commandFn: actions.toggleHangingProtocol
6437
6285
  },
6438
6286
  navigateHistory: {
6439
- commandFn: actions.navigateHistory,
6440
- storeContexts: [],
6441
- options: {}
6287
+ commandFn: actions.navigateHistory
6442
6288
  },
6443
6289
  nextStage: {
6444
6290
  commandFn: actions.deltaStage,
6445
- storeContexts: [],
6446
6291
  options: {
6447
6292
  direction: 1
6448
6293
  }
6449
6294
  },
6450
6295
  previousStage: {
6451
6296
  commandFn: actions.deltaStage,
6452
- storeContexts: [],
6453
6297
  options: {
6454
6298
  direction: -1
6455
6299
  }
6456
6300
  },
6457
6301
  setViewportGridLayout: {
6458
- commandFn: actions.setViewportGridLayout,
6459
- storeContexts: [],
6460
- options: {}
6302
+ commandFn: actions.setViewportGridLayout
6461
6303
  },
6462
6304
  toggleOneUp: {
6463
- commandFn: actions.toggleOneUp,
6464
- storeContexts: [],
6465
- options: {}
6305
+ commandFn: actions.toggleOneUp
6466
6306
  },
6467
6307
  openDICOMTagViewer: {
6468
6308
  commandFn: actions.openDICOMTagViewer
6469
6309
  },
6470
6310
  updateViewportDisplaySet: {
6471
- commandFn: actions.updateViewportDisplaySet,
6472
- storeContexts: [],
6473
- options: {}
6311
+ commandFn: actions.updateViewportDisplaySet
6474
6312
  }
6475
6313
  };
6476
6314
  return {
@@ -7673,11 +7511,16 @@ const init_metadataProvider = src.classes.MetadataProvider;
7673
7511
  */
7674
7512
  function init({
7675
7513
  servicesManager,
7676
- configuration = {}
7514
+ configuration = {},
7515
+ commandsManager
7677
7516
  }) {
7678
7517
  const {
7679
- stateSyncService
7518
+ stateSyncService,
7519
+ toolbarService,
7520
+ cineService,
7521
+ viewportGridService
7680
7522
  } = servicesManager.services;
7523
+ toolbarService.registerEventForToolbarUpdate(cineService, [cineService.EVENTS.CINE_STATE_CHANGED]);
7681
7524
  // Add
7682
7525
  src.DicomMetadataStore.subscribe(src.DicomMetadataStore.EVENTS.INSTANCES_ADDED, handlePETImageMetadata);
7683
7526
 
@@ -7692,6 +7535,12 @@ function init({
7692
7535
  clearOnModeExit: true
7693
7536
  });
7694
7537
 
7538
+ // uiStateStore is a sync state which stores the relevant
7539
+ // UI state for the viewer
7540
+ stateSyncService.register('uiStateStore', {
7541
+ clearOnModeExit: true
7542
+ });
7543
+
7695
7544
  // displaySetSelectorMap stores a map from
7696
7545
  // `<activeStudyUID>:<displaySetSelectorId>:<matchOffset>` to
7697
7546
  // a displaySetInstanceUID, used to display named display sets in
@@ -7708,7 +7557,7 @@ function init({
7708
7557
  });
7709
7558
 
7710
7559
  // Stores a map from the to be applied hanging protocols `<activeStudyUID>:<protocolId>`
7711
- // to the previously applied hanging protolStageIndexMap key, in order to toggle
7560
+ // to the previously applied hanging protocolStageIndexMap key, in order to toggle
7712
7561
  // off the applied protocol and remember the old state.
7713
7562
  stateSyncService.register('toggleHangingProtocol', {
7714
7563
  clearOnModeExit: true
@@ -7720,6 +7569,47 @@ function init({
7720
7569
  stateSyncService.register('viewportsByPosition', {
7721
7570
  clearOnModeExit: true
7722
7571
  });
7572
+
7573
+ // Function to process and subscribe to events for a given set of commands and listeners
7574
+ const subscribeToEvents = listeners => {
7575
+ Object.entries(listeners).forEach(([event, commands]) => {
7576
+ const supportedEvents = [viewportGridService.EVENTS.ACTIVE_VIEWPORT_ID_CHANGED, viewportGridService.EVENTS.VIEWPORTS_READY];
7577
+ if (supportedEvents.includes(event)) {
7578
+ viewportGridService.subscribe(event, eventData => {
7579
+ const viewportId = eventData?.viewportId ?? viewportGridService.getActiveViewportId();
7580
+ commandsManager.run(commands, {
7581
+ viewportId
7582
+ });
7583
+ });
7584
+ }
7585
+ });
7586
+ };
7587
+ toolbarService.subscribe(toolbarService.EVENTS.TOOL_BAR_MODIFIED, state => {
7588
+ const {
7589
+ buttons
7590
+ } = state;
7591
+ for (const [id, button] of Object.entries(buttons)) {
7592
+ const {
7593
+ groupId,
7594
+ items,
7595
+ listeners
7596
+ } = button.props;
7597
+
7598
+ // Handle group items' listeners
7599
+ if (groupId && items) {
7600
+ items.forEach(item => {
7601
+ if (item.listeners) {
7602
+ subscribeToEvents(item.listeners);
7603
+ }
7604
+ });
7605
+ }
7606
+
7607
+ // Handle button listeners
7608
+ if (listeners) {
7609
+ subscribeToEvents(listeners);
7610
+ }
7611
+ }
7612
+ });
7723
7613
  }
7724
7614
  const handlePETImageMetadata = ({
7725
7615
  SeriesInstanceUID,