@topconsultnpm/sdkui-react 6.21.0-dev2.8 → 6.21.0-dev3.2

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 (81) hide show
  1. package/lib/components/base/TMAccordionNew.js +1 -0
  2. package/lib/components/base/TMAreaManager.js +19 -3
  3. package/lib/components/base/TMDataGrid.js +2 -2
  4. package/lib/components/base/TMModal.d.ts +1 -0
  5. package/lib/components/base/TMModal.js +2 -2
  6. package/lib/components/base/TMPanel.d.ts +7 -4
  7. package/lib/components/base/TMPanel.js +58 -26
  8. package/lib/components/base/TMTreeView.js +12 -2
  9. package/lib/components/base/TMWaitPanel.d.ts +3 -1
  10. package/lib/components/base/TMWaitPanel.js +14 -9
  11. package/lib/components/choosers/TMDistinctValues.js +35 -21
  12. package/lib/components/choosers/TMUserChooser.d.ts +4 -0
  13. package/lib/components/choosers/TMUserChooser.js +7 -5
  14. package/lib/components/editors/TMFormulaEditor.d.ts +2 -0
  15. package/lib/components/editors/TMFormulaEditor.js +75 -21
  16. package/lib/components/editors/TMMetadataValues.js +2 -1
  17. package/lib/components/editors/TMRadioButton.js +7 -5
  18. package/lib/components/editors/TMTextBox.d.ts +2 -0
  19. package/lib/components/editors/TMTextBox.js +3 -3
  20. package/lib/components/features/archive/TMArchive.js +1 -1
  21. package/lib/components/features/documents/TMCopyToFolderForm.d.ts +24 -0
  22. package/lib/components/features/documents/TMCopyToFolderForm.js +401 -0
  23. package/lib/components/features/documents/TMDcmtForm.d.ts +1 -0
  24. package/lib/components/features/documents/TMDcmtForm.js +126 -38
  25. package/lib/components/features/documents/TMDcmtFormActionButtons.js +17 -2
  26. package/lib/components/features/documents/TMDcmtPreview.d.ts +1 -0
  27. package/lib/components/features/documents/TMDcmtPreview.js +2 -2
  28. package/lib/components/features/documents/TMDcmtTasks.d.ts +1 -0
  29. package/lib/components/features/documents/TMDcmtTasks.js +2 -2
  30. package/lib/components/features/documents/TMDownloadRelationViewerSection.d.ts +23 -0
  31. package/lib/components/features/documents/TMDownloadRelationViewerSection.js +173 -0
  32. package/lib/components/features/documents/TMFileUploader.js +1 -1
  33. package/lib/components/features/documents/TMMasterDetailDcmts.d.ts +2 -0
  34. package/lib/components/features/documents/TMMasterDetailDcmts.js +28 -9
  35. package/lib/components/features/documents/TMMergeToPdfForm.d.ts +24 -0
  36. package/lib/components/features/documents/TMMergeToPdfForm.js +309 -0
  37. package/lib/components/features/documents/TMRelationViewer.d.ts +13 -0
  38. package/lib/components/features/documents/TMRelationViewer.js +75 -6
  39. package/lib/components/features/documents/copyAndMergeDcmtsShared.d.ts +71 -0
  40. package/lib/components/features/documents/copyAndMergeDcmtsShared.js +304 -0
  41. package/lib/components/features/search/SignatureParamsManager.d.ts +70 -0
  42. package/lib/components/features/search/SignatureParamsManager.js +145 -0
  43. package/lib/components/features/search/TMSavedQuerySelector.d.ts +2 -2
  44. package/lib/components/features/search/TMSavedQuerySelector.js +3 -2
  45. package/lib/components/features/search/TMSearch.d.ts +4 -1
  46. package/lib/components/features/search/TMSearch.js +16 -10
  47. package/lib/components/features/search/TMSearchQueryPanel.js +1 -1
  48. package/lib/components/features/search/TMSearchResult.d.ts +2 -0
  49. package/lib/components/features/search/TMSearchResult.js +117 -22
  50. package/lib/components/features/workflow/diagram/queryDescriptorParser.js +3 -6
  51. package/lib/components/forms/Login/TMLoginForm.d.ts +9 -0
  52. package/lib/components/forms/Login/TMLoginForm.js +61 -0
  53. package/lib/components/forms/TMResultDialog.d.ts +1 -1
  54. package/lib/components/forms/TMResultDialog.js +4 -2
  55. package/lib/components/index.d.ts +1 -0
  56. package/lib/components/index.js +1 -0
  57. package/lib/components/pages/TMPage.js +3 -1
  58. package/lib/components/query/TMQueryEditor.js +1 -1
  59. package/lib/components/viewers/TMTidViewer.js +1 -1
  60. package/lib/helper/MergePdfManager.d.ts +45 -0
  61. package/lib/helper/MergePdfManager.js +145 -0
  62. package/lib/helper/SDKUI_Globals.d.ts +15 -0
  63. package/lib/helper/SDKUI_Globals.js +15 -1
  64. package/lib/helper/SDKUI_Localizator.d.ts +107 -2
  65. package/lib/helper/SDKUI_Localizator.js +1070 -12
  66. package/lib/helper/TMPdfViewer.js +25 -24
  67. package/lib/helper/TMUtils.d.ts +1 -0
  68. package/lib/helper/TMUtils.js +17 -0
  69. package/lib/helper/ZipManager.d.ts +56 -0
  70. package/lib/helper/ZipManager.js +127 -0
  71. package/lib/helper/index.d.ts +1 -0
  72. package/lib/helper/index.js +1 -0
  73. package/lib/hooks/useDataUserIdItem.js +6 -4
  74. package/lib/hooks/useDcmtOperations.d.ts +9 -2
  75. package/lib/hooks/useDcmtOperations.js +77 -34
  76. package/lib/hooks/useDocumentOperations.d.ts +3 -0
  77. package/lib/hooks/useDocumentOperations.js +233 -24
  78. package/lib/hooks/useForm.js +5 -2
  79. package/lib/hooks/useResizeObserver.d.ts +1 -1
  80. package/lib/hooks/useResizeObserver.js +16 -15
  81. package/package.json +4 -2
@@ -252,6 +252,7 @@ const TMAccordion = ({ groups, localStorageKey, selectedItem, onSelectedItemChan
252
252
  disabled: mi.disabled,
253
253
  onClick: mi.onClick,
254
254
  submenu: mi.items || mi.submenu,
255
+ beginGroup: mi.beginGroup ?? false
255
256
  }));
256
257
  setItemContextMenuPosition({ x: event.clientX, y: event.clientY });
257
258
  setItemContextMenuItems(convertedItems);
@@ -5,7 +5,7 @@ import { FileDescriptor, FileFormats, FileTransferModes, SDK_Localizator, SDK_Gl
5
5
  import CustomFileSystemProvider from 'devextreme/file_management/custom_provider';
6
6
  import FileSystemError from "devextreme/file_management/error";
7
7
  import Button from "devextreme/ui/button";
8
- import { alert, confirm } from "devextreme/ui/dialog";
8
+ import { alert, custom } from "devextreme/ui/dialog";
9
9
  import { loadMessages } from 'devextreme/localization';
10
10
  import { getFileManagerFolderColor, Globalization, IconAll, IconCloud, IconFolder, IconFolderForCSS, IconSelected, SDKUI_Localizator, svgToString } from '../../helper';
11
11
  import { TMExceptionBoxManager } from './TMPopUp';
@@ -253,8 +253,24 @@ const TMAreaManager = (props = { selectionMode: 'multiple', isPathChooser: false
253
253
  else {
254
254
  msg = SDKUI_Localizator.FileManager_QuestionAlreadyExistsFiles.replaceParams(resolvesForExistingFiles.length.toString());
255
255
  }
256
- const result = confirm(msg, SDKUI_Localizator.Attention);
257
- result.then((dialogResult) => {
256
+ const confirmDialog = custom({
257
+ title: SDKUI_Localizator.Attention,
258
+ messageHtml: `<div style="padding: 15px; font-size: 1rem; max-width: 500px; word-wrap: break-word; overflow-wrap: break-word;">${msg}</div>`,
259
+ buttons: [
260
+ {
261
+ text: SDKUI_Localizator.Yes ?? "Yes",
262
+ onClick: () => true,
263
+ type: "default",
264
+ stylingMode: "contained"
265
+ },
266
+ {
267
+ text: SDKUI_Localizator.No ?? "No",
268
+ onClick: () => false,
269
+ stylingMode: "outlined"
270
+ }
271
+ ]
272
+ });
273
+ confirmDialog.show().then((dialogResult) => {
258
274
  resolvesForNonExistingFiles.forEach((res) => {
259
275
  res({
260
276
  cancel: false,
@@ -22,7 +22,7 @@ const TMDataGrid = React.forwardRef((props, ref) => {
22
22
  // events and callbacks
23
23
  onSelectionChanged, onFocusedRowChanged, onRowDblClick, onRowClick, onCellClick, onCellDblClick, onOptionChanged, onContentReady, onContextMenuPreparing, onInitialized, onEditorPreparing, onCellPrepared, onRowPrepared, onRowUpdating, onRowExpanded, onRowCollapsed, onRowUpdated, onSaved, onEditCanceled, onEditingStart, onEditingChange, customizeColumns, onKeyDown, scrolling = { mode: 'standard', useNative: SDKUI_Globals.userSettings?.themeSettings.gridSettings.useNativeScrollbar === 1 }, paging = { enabled: true, pageSize: pageSize }, pager = { visible: true, showInfo: true, showNavigationButtons: true }, selection = { mode: 'multiple', showCheckBoxesMode: "always", selectAllMode: "allPages" }, sorting, summary, stateStoring, grouping, groupPanel, filterRow, headerFilter, editing, rowDragging, masterDetail,
24
24
  // other properties
25
- disabled = false, autoNavigateToFocusedRow = true, columnResizingMode = 'widget', columnHidingEnabled = true, columnAutoWidth = true, allowColumnResizing = true, allowColumnReordering = true, showBorders = true, showRowLines = SDKUI_Globals.userSettings?.themeSettings.gridSettings.showRowLines === 1, showColumnLines = SDKUI_Globals.userSettings?.themeSettings.gridSettings.showColumnLines === 1, showColumnHeaders = true, rowAlternationEnabled = false, wordWrapEnabled = false, noDataText,
25
+ disabled = false, autoNavigateToFocusedRow = true, columnResizingMode = 'widget', columnHidingEnabled = true, columnAutoWidth = true, allowColumnResizing = true, allowColumnReordering = true, showBorders = true, showRowLines = SDKUI_Globals.userSettings?.themeSettings.gridSettings.showRowLines === 1, showColumnLines = SDKUI_Globals.userSettings?.themeSettings.gridSettings.showColumnLines === 1, showColumnHeaders = true, rowAlternationEnabled = false, wordWrapEnabled = false, noDataText, columnMinWidth,
26
26
  // styles
27
27
  id, width = '100%', height = '100%', } = props;
28
28
  const internalRef = React.useRef(null);
@@ -354,7 +354,7 @@ const TMDataGrid = React.forwardRef((props, ref) => {
354
354
  // events and callbacks
355
355
  onSelectionChanged: onSelectionChangedCallback, onRowDblClick: onRowDblClickCallback, onRowPrepared: onRowPrepared, onContextMenuPreparing: onContextMenuPreparingCallback, onToolbarPreparing: onToolbarPreparingCallback, onFocusedRowChanged: onFocusedRowChanged, onRowClick: onRowClick, onCellClick: onCellClick, onCellDblClick: onCellDblClick, onOptionChanged: onOptionChangedCallback, onContentReady: onContentReadyCallback, onInitialized: onInitialized, customizeColumns: customizeColumns, onEditorPreparing: onEditorPreparing, onCellPrepared: onCellPrepared, onRowUpdating: onRowUpdating, onRowExpanded: onRowExpanded, onRowCollapsed: onRowCollapsed, onRowUpdated: onRowUpdated, onSaved: onSaved, onEditCanceled: onEditCanceled, onEditingStart: onEditingStart, onEditingChange: onEditingChange, onKeyDown: onKeyDown,
356
356
  // other properties
357
- disabled: disabled, autoNavigateToFocusedRow: autoNavigateToFocusedRow, focusedRowKey: focusedRowKey, columnHidingEnabled: columnHidingEnabled, columnResizingMode: columnResizingMode, columnAutoWidth: columnAutoWidth, allowColumnResizing: allowColumnResizing, allowColumnReordering: allowColumnReordering, showBorders: showBorders, showRowLines: showRowLines, showColumnLines: showColumnLines, showColumnHeaders: showColumnHeaders, rowAlternationEnabled: rowAlternationEnabled, wordWrapEnabled: wordWrapEnabled, noDataText: noDataText,
357
+ disabled: disabled, autoNavigateToFocusedRow: autoNavigateToFocusedRow, focusedRowKey: focusedRowKey, columnHidingEnabled: columnHidingEnabled, columnResizingMode: columnResizingMode, columnAutoWidth: columnAutoWidth, allowColumnResizing: allowColumnResizing, allowColumnReordering: allowColumnReordering, showBorders: showBorders, showRowLines: showRowLines, showColumnLines: showColumnLines, showColumnHeaders: showColumnHeaders, rowAlternationEnabled: rowAlternationEnabled, wordWrapEnabled: wordWrapEnabled, columnMinWidth: columnMinWidth, noDataText: noDataText,
358
358
  // styles
359
359
  width: width, height: height, style: {
360
360
  userSelect: 'none',
@@ -13,6 +13,7 @@ interface ITMModal {
13
13
  hidePopup?: boolean;
14
14
  askClosingConfirm?: boolean;
15
15
  showCloseButton?: boolean;
16
+ showHeader?: boolean;
16
17
  }
17
18
  declare const TMModal: React.FC<ITMModal>;
18
19
  export default TMModal;
@@ -39,7 +39,7 @@ const StyledModalContext = styled.div `
39
39
  overflow: auto;
40
40
  height: 100%;
41
41
  `;
42
- const TMModal = ({ resizable = true, expandable = false, isModal = true, title = '', toolbar, onClose, children, width = '100%', height = '100%', fontSize = FontSize.defaultFontSize, hidePopup = true, askClosingConfirm = false, showCloseButton = true }) => {
42
+ const TMModal = ({ resizable = true, expandable = false, isModal = true, title = '', toolbar, onClose, children, width = '100%', height = '100%', fontSize = FontSize.defaultFontSize, hidePopup = true, askClosingConfirm = false, showCloseButton = true, showHeader = true }) => {
43
43
  const popupRef = useRef(null);
44
44
  const [initialWidth, setInitialWidth] = useState(width);
45
45
  const [initialHeight, setInitialHeight] = useState(height);
@@ -101,7 +101,7 @@ const TMModal = ({ resizable = true, expandable = false, isModal = true, title =
101
101
  setShowPopup(false);
102
102
  onClose && onClose();
103
103
  };
104
- return (_jsx(_Fragment, { children: isModal ? (_jsx(Popup, { ref: popupRef, showCloseButton: showCloseButton, animation: undefined, minWidth: minWidth, minHeight: minHeight, maxHeight: '95%', maxWidth: '95%', dragEnabled: !isResizing, resizeEnabled: resizable, width: expandable && isFullScreen ? '95%' : initialWidth, height: expandable && isFullScreen ? '95%' : initialHeight, title: title, visible: showPopup, onShown: handleShown, onResizeStart: handleResizeStart, onResizeEnd: handleResizeEnd, onHiding: onHiding, toolbarItems: expandable ? [
104
+ return (_jsx(_Fragment, { children: isModal ? (_jsx(Popup, { ref: popupRef, showCloseButton: showHeader ? showCloseButton : false, showTitle: showHeader, animation: undefined, minWidth: minWidth, minHeight: minHeight, maxHeight: '95%', maxWidth: '95%', dragEnabled: !isResizing, resizeEnabled: resizable, width: expandable && isFullScreen ? '95%' : initialWidth, height: expandable && isFullScreen ? '95%' : initialHeight, title: title, visible: showPopup, onShown: handleShown, onResizeStart: handleResizeStart, onResizeEnd: handleResizeEnd, onHiding: onHiding, toolbarItems: showHeader && expandable ? [
105
105
  {
106
106
  widget: 'dxButton',
107
107
  location: 'after',
@@ -1,7 +1,3 @@
1
- /** Gestione TMPanel "attivo / non attivo" secondo una pattern ibrido (Controlled/Uncontrolled Component):
2
- 1) Modalità Non Controllata (Uncontrolled): Se non gli viene passata la prop "isActive", il pannello gestisce lo stato "attivo" internamente. Per l'uso singolo ("plug-and-play").
3
- 2) Modalità Controllata (Controlled): Se il genitore passa la prop "isActive", il pannello cede il controllo e si affida completamente al genitore. Ideale per layout con più pannelli che necessitano di coordinamento.
4
- */
5
1
  import React from 'react';
6
2
  export interface ITMPanelRef {
7
3
  focusPanel: () => void;
@@ -28,5 +24,12 @@ export interface ITMPanelProps {
28
24
  onHeaderDoubleClick?: () => void;
29
25
  onMaximize?: (isMaximized: boolean) => void;
30
26
  }
27
+ /**
28
+ * TMPanel - Pannello con supporto Controlled/Uncontrolled
29
+ *
30
+ * @prop isActive (opzionale)
31
+ * - Se NON passata → Uncontrolled: gestione interna dello stato attivo (plug-and-play)
32
+ * - Se passata → Controlled: il parent gestisce lo stato tramite onActivate
33
+ */
31
34
  declare const TMPanel: React.ForwardRefExoticComponent<ITMPanelProps & React.RefAttributes<ITMPanelRef>>;
32
35
  export default TMPanel;
@@ -1,14 +1,35 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- /** Gestione TMPanel "attivo / non attivo" secondo una pattern ibrido (Controlled/Uncontrolled Component):
3
- 1) Modalità Non Controllata (Uncontrolled): Se non gli viene passata la prop "isActive", il pannello gestisce lo stato "attivo" internamente. Per l'uso singolo ("plug-and-play").
4
- 2) Modalità Controllata (Controlled): Se il genitore passa la prop "isActive", il pannello cede il controllo e si affida completamente al genitore. Ideale per layout con più pannelli che necessitano di coordinamento.
5
- */
6
2
  import { useCallback, useRef, useState, forwardRef, useImperativeHandle } from 'react';
7
3
  import styled from 'styled-components';
8
4
  import { getAppModuleGradient, IconArrowLeft, IconClearButton, IconWindowMaximize, IconWindowMinimize, isPositiveNumber, SDKUI_Localizator } from '../../helper';
9
5
  import TMButton from './TMButton';
10
6
  import { Gutters } from '../../utils/theme';
7
+ const StyledBackButton = styled.button `
8
+ display: flex;
9
+ align-items: center;
10
+ justify-content: center;
11
+ gap: 4px;
12
+ padding: 4px 10px;
13
+ border: 1px solid ${({ $isActive }) => $isActive ? 'rgba(37, 89, 165, 0.3)' : 'rgba(255, 255, 255, 0.4)'};
14
+ border-radius: 6px;
15
+ cursor: pointer;
16
+ font-weight: 500;
17
+ font-size: 0.85rem;
18
+ flex-shrink: 0;
19
+ transition: all 0.15s ease;
20
+ background-color: ${({ $isActive }) => $isActive ? '#FFFFFF' : '#2559A5'};
21
+ box-shadow: none;
22
+
23
+ &&, && * {
24
+ color: ${({ $isActive }) => $isActive ? '#2559A5' : '#FFFFFF'} !important;
25
+ }
26
+
27
+ svg {
28
+ font-size: 14px;
29
+ }
30
+ `;
11
31
  import { AppModules, SDK_Globals } from '@topconsultnpm/sdk-ts';
32
+ import { DeviceType, useDeviceType } from './TMDeviceProvider';
12
33
  const StyledPanelContainer = styled.div `
13
34
  width: 100%;
14
35
  height: 100%;
@@ -75,9 +96,19 @@ const StyledPanelContent = styled.div `
75
96
  outline: none;
76
97
  }
77
98
  `;
99
+ /**
100
+ * TMPanel - Pannello con supporto Controlled/Uncontrolled
101
+ *
102
+ * @prop isActive (opzionale)
103
+ * - Se NON passata → Uncontrolled: gestione interna dello stato attivo (plug-and-play)
104
+ * - Se passata → Controlled: il parent gestisce lo stato tramite onActivate
105
+ */
78
106
  const TMPanel = forwardRef(({ allowMaximize = true, color, backgroundColor, backgroundColorContainer, children, showHeader = true, title, totalItems, displayedItemsCount, toolbar, padding = '5px', isVisible = true, panelID = 'tmpanel', isActive, // Questa prop determinerà la modalità
79
107
  onActivate, onBack, onClose, onHeaderDoubleClick, onMaximize, onActiveChanged }, ref) => {
80
108
  const [isMaximized, setIsMaximized] = useState(false);
109
+ // Detect device type (e.g., mobile or desktop)
110
+ const deviceType = useDeviceType();
111
+ const isMobile = deviceType === DeviceType.MOBILE;
81
112
  // INTERNAL STATUS for UNCONTROLLED mode
82
113
  const [internalIsActive, setInternalIsActive] = useState(false);
83
114
  const panelRef = useRef(null);
@@ -149,36 +180,37 @@ onActivate, onBack, onClose, onHeaderDoubleClick, onMaximize, onActiveChanged },
149
180
  flexDirection: 'row',
150
181
  alignItems: 'center',
151
182
  width: '100%',
152
- minWidth: 0
153
- }, children: [_jsxs("div", { style: {
183
+ minWidth: 0,
184
+ flexWrap: 'nowrap',
185
+ overflow: 'hidden'
186
+ }, children: [onBack && _jsx("div", { style: {
154
187
  display: 'flex',
155
188
  flexDirection: 'row',
156
189
  alignItems: 'center',
157
- gap: '8px',
190
+ flexShrink: 0
191
+ }, children: _jsxs(StyledBackButton, { "$isActive": currentIsActive, onClick: () => onBack ? onBack() : null, title: SDKUI_Localizator.Back, children: [_jsx(IconArrowLeft, {}), !isMobile && _jsx("span", { children: SDKUI_Localizator.Back })] }) }), _jsx("div", { style: {
158
192
  flex: 1,
159
- minWidth: 0
160
- }, children: [onBack &&
161
- _jsx(TMButton, { btnStyle: 'icon', icon: _jsx(IconArrowLeft, {}), caption: SDKUI_Localizator.Back, onClick: onBack }), _jsx("div", { style: {
162
- display: 'flex',
163
- flexDirection: 'row',
164
- alignItems: 'center',
165
- overflow: 'hidden',
166
- }, children: _jsxs("div", { style: {
167
- whiteSpace: 'nowrap',
168
- overflow: 'hidden',
169
- textOverflow: 'ellipsis',
170
- margin: 0
171
- }, children: [title, isPositiveNumber(displayedItemsCount) && isPositiveNumber(totalItems)
172
- ? ` (${displayedItemsCount} / ${totalItems})`
173
- : isPositiveNumber(totalItems)
174
- ? ` (${totalItems})`
175
- : ''] }) })] }), _jsxs("div", { style: {
193
+ display: 'flex',
194
+ alignItems: 'center',
195
+ justifyContent: 'flex-start',
196
+ minWidth: 0,
197
+ overflow: 'hidden',
198
+ padding: '0 8px'
199
+ }, children: _jsxs("div", { style: {
200
+ whiteSpace: 'nowrap',
201
+ overflow: 'hidden',
202
+ textOverflow: 'ellipsis',
203
+ margin: 0
204
+ }, children: [title, isPositiveNumber(displayedItemsCount) && isPositiveNumber(totalItems)
205
+ ? ` (${displayedItemsCount} / ${totalItems})`
206
+ : isPositiveNumber(totalItems)
207
+ ? ` (${totalItems})`
208
+ : ''] }) }), _jsxs("div", { style: {
176
209
  display: 'flex',
177
210
  flexDirection: 'row',
178
211
  alignItems: 'center',
179
212
  gap: '5px',
180
- flexShrink: 0,
181
- marginLeft: 10
213
+ flexShrink: 0
182
214
  }, children: [toolbar, allowMaximize && _jsx(TMButton, { color: 'primaryOutline', caption: isMaximized ? SDKUI_Localizator.Minimize : SDKUI_Localizator.Maximize, icon: isMaximized
183
215
  ? _jsx(IconWindowMinimize, { fontSize: 16 })
184
216
  : _jsx(IconWindowMaximize, { fontSize: 16 }), btnStyle: 'icon', onClick: handleMaximize }), onClose && _jsx(TMButton, { color: 'primaryOutline', caption: SDKUI_Localizator.Close, icon: _jsx(IconClearButton, {}), btnStyle: 'icon', onClick: () => { setIsMaximized(false); onClose?.(); } })] })] }) }), _jsx(StyledPanelContent, { "$height": showHeader ? "calc(100% - 40px)" : "100%", "$padding": padding, "$backgroundColor": backgroundColorContainer ?? `#FFFFFF`, children: children })] }));
@@ -9,23 +9,28 @@ const TMTreeView = ({ dataSource = [], focusedItem, selectedItems = [], allowMul
9
9
  if (!focusedItem)
10
10
  return;
11
11
  let newFocusedItem = null;
12
+ let handled = false;
12
13
  switch (event.key) {
13
14
  case 'ArrowDown':
14
15
  newFocusedItem = findNextItem(dataSource, focusedItem);
16
+ handled = true;
15
17
  break;
16
18
  case 'ArrowUp':
17
19
  newFocusedItem = findPreviousItem(dataSource, focusedItem);
20
+ handled = true;
18
21
  break;
19
22
  case '+':
20
23
  if (!focusedItem.expanded) {
21
24
  handleNodeToggle(focusedItem.key, false);
22
25
  newFocusedItem = { ...focusedItem, expanded: true };
26
+ handled = true;
23
27
  }
24
28
  break;
25
29
  case '-':
26
30
  if (focusedItem.expanded) {
27
31
  handleNodeToggle(focusedItem.key, false);
28
32
  newFocusedItem = { ...focusedItem, expanded: false };
33
+ handled = true;
29
34
  }
30
35
  break;
31
36
  // case ' ':
@@ -40,12 +45,17 @@ const TMTreeView = ({ dataSource = [], focusedItem, selectedItems = [], allowMul
40
45
  default:
41
46
  break;
42
47
  }
48
+ if (handled) {
49
+ event.preventDefault();
50
+ event.stopPropagation();
51
+ }
43
52
  if (newFocusedItem)
44
53
  onFocusedItemChanged?.(newFocusedItem);
45
54
  };
46
- window.addEventListener('keydown', handleKeyDown);
55
+ // Usa capture: true per intercettare l'evento PRIMA che DevExtreme Popup lo gestisca
56
+ window.addEventListener('keydown', handleKeyDown, true);
47
57
  return () => {
48
- window.removeEventListener('keydown', handleKeyDown);
58
+ window.removeEventListener('keydown', handleKeyDown, true);
49
59
  };
50
60
  }, [focusedItem, dataSource, onFocusedItemChanged]);
51
61
  const findNextItem = (nodes, currentItem) => {
@@ -12,6 +12,7 @@ interface ITMWaitPanelProps {
12
12
  isCancelable?: boolean;
13
13
  abortController?: AbortController;
14
14
  onAbortClick?: (abortController: AbortController | undefined) => void;
15
+ useHighZIndex?: boolean;
15
16
  }
16
17
  export declare const TMWaitPanel: (props: ITMWaitPanelProps) => import("react/jsx-runtime").JSX.Element;
17
18
  interface ITMLayoutWaitingContainerProps extends ITMLayoutContainerProps {
@@ -27,6 +28,7 @@ interface ITMLayoutWaitingContainerProps extends ITMLayoutContainerProps {
27
28
  waitPanelMaxValueSecondary?: number;
28
29
  isCancelable?: boolean;
29
30
  abortController?: AbortController;
31
+ usePortal?: boolean;
30
32
  }
31
- export declare const TMLayoutWaitingContainer: ({ showWaitPanel, showWaitPanelPrimary, showWaitPanelSecondary, waitPanelTitle, waitPanelTextSecondary, waitPanelValueSecondary, waitPanelMaxValueSecondary, waitPanelTextPrimary, waitPanelValuePrimary, waitPanelMaxValuePrimary, isCancelable, abortController, gap, onClick, justifyContent, alignItems, children, direction }: ITMLayoutWaitingContainerProps) => import("react/jsx-runtime").JSX.Element;
33
+ export declare const TMLayoutWaitingContainer: ({ showWaitPanel, showWaitPanelPrimary, showWaitPanelSecondary, waitPanelTitle, waitPanelTextSecondary, waitPanelValueSecondary, waitPanelMaxValueSecondary, waitPanelTextPrimary, waitPanelValuePrimary, waitPanelMaxValuePrimary, isCancelable, abortController, usePortal, gap, onClick, justifyContent, alignItems, children, direction }: ITMLayoutWaitingContainerProps) => import("react/jsx-runtime").JSX.Element;
32
34
  export {};
@@ -1,4 +1,5 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { createPortal } from 'react-dom';
2
3
  import styled from 'styled-components';
3
4
  import TMLayoutContainer from './TMLayout';
4
5
  import { SDKUI_Localizator } from '../../helper';
@@ -8,7 +9,7 @@ const StyledWaitPanelOverlay = styled.div `
8
9
  position: fixed;
9
10
  top: 0;
10
11
  left: 0;
11
- z-index: 1501;
12
+ z-index: ${props => props.$useHighZIndex ? 2000000001 : 1501};
12
13
  transition: all;
13
14
  overflow: visible;
14
15
  background-color: rgba(0, 0, 0, 0.4);
@@ -18,13 +19,16 @@ const StyledWaitPanel = styled.div `
18
19
  top: 50%;
19
20
  left: 50%;
20
21
  transform: translate(-50%, -50%);
21
- width: 300px;
22
- height: ${(props) => props.$height};
22
+ width: 300px;
23
+ max-width: calc(100% - 20px);
24
+ height: auto;
25
+ max-height: calc(100% - 20px);
23
26
  background: white;
24
27
  border-radius: 8px;
25
28
  padding: 10px;
26
29
  text-align: center;
27
- box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
30
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
31
+ overflow: auto;
28
32
  `;
29
33
  const StyledTitle = styled.h2 ` margin: 0; font-size: 1.5em; color: #333; `;
30
34
  const StyledProgressBarContainer = styled.div ` width: 100%; height: 20px; background: #e0e0e0; border-radius: 10px; overflow: hidden; margin: 20px 0; `;
@@ -33,7 +37,7 @@ const StyledProgressText = styled.p ` font-weight: bold; color: #333; margin: 0;
33
37
  const StyledMessage = styled.p ` color: #666; font-size: 0.9em; margin-top: 10px; `;
34
38
  const StyledAbortButton = styled.button ` background: #ff4d4d; color: white; border: none; border-radius: 5px; padding: 10px 20px; font-size: 1em; cursor: pointer; margin-top: 20px; &:hover { background: #ff6666; } `;
35
39
  export const TMWaitPanel = (props) => {
36
- const { title, showPrimary, textPrimary, valuePrimary, maxValuePrimary, showSecondary, textSecondary, valueSecondary, maxValueSecondary, isCancelable, abortController, onAbortClick } = props;
40
+ const { title, showPrimary, textPrimary, valuePrimary, maxValuePrimary, showSecondary, textSecondary, valueSecondary, maxValueSecondary, isCancelable, abortController, onAbortClick, useHighZIndex } = props;
37
41
  const calculateProgress = (value = 0, maxValue = 0) => {
38
42
  if (maxValue === 0)
39
43
  return 0;
@@ -42,10 +46,11 @@ export const TMWaitPanel = (props) => {
42
46
  };
43
47
  let progressValue1 = calculateProgress(valuePrimary, maxValuePrimary);
44
48
  let progressValue2 = calculateProgress(valueSecondary, maxValueSecondary);
45
- return (_jsx(StyledWaitPanelOverlay, { children: _jsxs(StyledWaitPanel, { "$height": (showPrimary && showSecondary) ? '350px' : '250px', children: [_jsx(StyledTitle, { children: title }), showPrimary &&
49
+ return (_jsx(StyledWaitPanelOverlay, { "$useHighZIndex": useHighZIndex, children: _jsxs(StyledWaitPanel, { children: [_jsx(StyledTitle, { children: title }), showPrimary &&
46
50
  _jsxs("div", { style: { width: '100%', height: '100px' }, children: [_jsx(StyledProgressBarContainer, { children: _jsx(StyledProgressBar, { style: { width: `${progressValue1.toFixed(2)}%` } }) }), _jsxs(StyledProgressText, { children: [progressValue1.toFixed(2), "%"] }), _jsx(StyledMessage, { children: textPrimary })] }), showSecondary &&
47
51
  _jsxs("div", { style: { width: '100%', height: '100px' }, children: [_jsx(StyledProgressBarContainer, { children: _jsx(StyledProgressBar, { style: { width: `${progressValue2.toFixed(2)}%` } }) }), _jsxs(StyledProgressText, { children: [progressValue2.toFixed(2), "%"] }), _jsx(StyledMessage, { children: textSecondary })] }), isCancelable && _jsx(StyledAbortButton, { onClick: () => onAbortClick?.(abortController), children: SDKUI_Localizator.Abort })] }) }));
48
52
  };
49
- export const TMLayoutWaitingContainer = ({ showWaitPanel, showWaitPanelPrimary, showWaitPanelSecondary, waitPanelTitle, waitPanelTextSecondary, waitPanelValueSecondary, waitPanelMaxValueSecondary, waitPanelTextPrimary, waitPanelValuePrimary, waitPanelMaxValuePrimary, isCancelable, abortController, gap = 3, onClick, justifyContent = 'flex-start', alignItems = 'flex-start', children, direction = 'vertical' }) => {
50
- return (_jsxs(TMLayoutContainer, { gap: gap, justifyContent: justifyContent, alignItems: alignItems, direction: direction, children: [children, showWaitPanel && (_jsx(TMWaitPanel, { title: waitPanelTitle, showPrimary: showWaitPanelPrimary, textPrimary: waitPanelTextPrimary, valuePrimary: waitPanelValuePrimary, maxValuePrimary: waitPanelMaxValuePrimary, showSecondary: showWaitPanelSecondary, textSecondary: waitPanelTextSecondary, valueSecondary: waitPanelValueSecondary, maxValueSecondary: waitPanelMaxValueSecondary, isCancelable: isCancelable, abortController: abortController, onAbortClick: (abortController) => { setTimeout(() => { abortController?.abort(); }, 1000); } }))] }));
53
+ export const TMLayoutWaitingContainer = ({ showWaitPanel, showWaitPanelPrimary, showWaitPanelSecondary, waitPanelTitle, waitPanelTextSecondary, waitPanelValueSecondary, waitPanelMaxValueSecondary, waitPanelTextPrimary, waitPanelValuePrimary, waitPanelMaxValuePrimary, isCancelable, abortController, usePortal = false, gap = 3, onClick, justifyContent = 'flex-start', alignItems = 'flex-start', children, direction = 'vertical' }) => {
54
+ const waitPanelElement = showWaitPanel ? (_jsx(TMWaitPanel, { title: waitPanelTitle, showPrimary: showWaitPanelPrimary, textPrimary: waitPanelTextPrimary, valuePrimary: waitPanelValuePrimary, maxValuePrimary: waitPanelMaxValuePrimary, showSecondary: showWaitPanelSecondary, textSecondary: waitPanelTextSecondary, valueSecondary: waitPanelValueSecondary, maxValueSecondary: waitPanelMaxValueSecondary, isCancelable: isCancelable, abortController: abortController, onAbortClick: (abortController) => { setTimeout(() => { abortController?.abort(); }, 1000); }, useHighZIndex: usePortal })) : null;
55
+ return (_jsxs(_Fragment, { children: [usePortal && waitPanelElement && createPortal(waitPanelElement, document.body), _jsxs(TMLayoutContainer, { gap: gap, justifyContent: justifyContent, alignItems: alignItems, direction: direction, children: [children, !usePortal && waitPanelElement] })] }));
51
56
  };
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { useCallback, useEffect, useMemo, useState } from 'react';
3
- import { LayoutModes, MetadataDataDomains, AccessLevels, MetadataDataTypes, SDK_Globals, DcmtTypeListCacheService, DataColumnTypes } from '@topconsultnpm/sdk-ts';
3
+ import { LayoutModes, MetadataDataDomains, AccessLevels, MetadataDataTypes, SDK_Globals, DcmtTypeListCacheService, DataColumnTypes, DataListViewModes } from '@topconsultnpm/sdk-ts';
4
4
  import styled from 'styled-components';
5
5
  import { SDKUI_Localizator, stringIsNullOrEmpty } from '../../helper';
6
6
  import TMDataGrid, { TMDataGridPageSize } from '../base/TMDataGrid';
@@ -9,14 +9,17 @@ import TMSpinner from '../base/TMSpinner';
9
9
  import TMCheckBox from '../editors/TMCheckBox';
10
10
  import TMPanel from '../base/TMPanel';
11
11
  import TMModal from '../base/TMModal';
12
+ import { useDataListItem } from '../../hooks/useDataListItem';
13
+ import { useDataUserIdItem } from '../../hooks/useDataUserIdItem';
12
14
  const StyledDistinctValues = styled.div `display: flex; flex-direction: column; height: 100%; overflow: hidden; gap: 10px;`;
13
- const StyledPanelContainer = styled.div ` width: 100%; height: 100%; padding: 20px; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 20px; `;
14
15
  const TMDistinctValues = ({ tid, mid, layoutMode = LayoutModes.None, allowAppendMode = true, showHeader = true, isModal, separator = " ", onSelectionChanged, onClosePanelCallback }) => {
15
16
  const [focusedItem, setFocusedItem] = useState();
16
17
  const [dataSource, setDataSource] = useState([]);
17
18
  const [isAppendMode, setIsAppendMode] = useState(false);
18
19
  const [md, setMd] = useState();
19
20
  const [currentValue, setCurrentValue] = useState('');
21
+ const { loadDataListsAsync, renderDataListCell, dataListsCache } = useDataListItem();
22
+ const { loadUsersAsync, renderUserIdViewer, usersCache } = useDataUserIdItem();
20
23
  useEffect(() => {
21
24
  getDistictValuesAsync();
22
25
  }, [mid]);
@@ -57,8 +60,23 @@ const TMDistinctValues = ({ tid, mid, layoutMode = LayoutModes.None, allowAppend
57
60
  try {
58
61
  TMSpinner.show({ description: 'Caricamento dei valori distinti...' });
59
62
  let dtd = await DcmtTypeListCacheService.GetAsync(tid, true);
60
- setMd(dtd?.metadata?.find(o => o.id === mid));
63
+ const currentMd = dtd?.metadata?.find(o => o.id === mid);
64
+ setMd(currentMd);
61
65
  let result = await SDK_Globals.tmSession?.NewSearchEngine().GetDistinctValuesAsync(tid, mid, 10000);
66
+ // Load DataList or UserID cache based on metadata domain
67
+ if (currentMd?.dataDomain === MetadataDataDomains.DataList && currentMd.dataListID) {
68
+ await loadDataListsAsync(new Set([currentMd.dataListID]));
69
+ }
70
+ if (currentMd?.dataDomain === MetadataDataDomains.UserID && result?.dtdResult?.rows) {
71
+ const userIDs = new Set();
72
+ result.dtdResult.rows.forEach((row) => {
73
+ const userId = Number(row[0]);
74
+ if (userId && userId > 0) {
75
+ userIDs.add(userId);
76
+ }
77
+ });
78
+ await loadUsersAsync(userIDs);
79
+ }
62
80
  setDataSource(convertDataTableToObject(result?.dtdResult));
63
81
  }
64
82
  catch (e) {
@@ -69,31 +87,27 @@ const TMDistinctValues = ({ tid, mid, layoutMode = LayoutModes.None, allowAppend
69
87
  TMSpinner.hide();
70
88
  }
71
89
  };
72
- const getDcmtTypeAsync = async () => {
73
- if (!tid)
74
- return;
75
- try {
76
- TMSpinner.show({ description: 'Caricamento dei valori distinti...' });
77
- let dtd = await DcmtTypeListCacheService.GetAsync(tid, true);
78
- setMd(dtd?.metadata?.find(o => o.id === mid));
79
- }
80
- catch (e) {
81
- let err = e;
82
- TMExceptionBoxManager.show({ exception: err });
83
- }
84
- finally {
85
- TMSpinner.hide();
86
- }
87
- };
88
90
  const onFocusedRowChanged = useCallback((e) => {
89
91
  setFocusedItem(e.row?.data);
90
92
  }, []);
93
+ const valueCellRender = useCallback((cellData) => {
94
+ if (!cellData || cellData.value === undefined)
95
+ return null;
96
+ if (md?.dataDomain === MetadataDataDomains.DataList && md.dataListID) {
97
+ return renderDataListCell(cellData.value, md.dataListID, md.dataListViewMode ?? DataListViewModes.None);
98
+ }
99
+ if (md?.dataDomain === MetadataDataDomains.UserID) {
100
+ return renderUserIdViewer(Number(cellData.value), true);
101
+ }
102
+ return _jsx("div", { children: cellData.text });
103
+ }, [md, renderDataListCell, renderUserIdViewer]);
91
104
  const customColumns = useMemo(() => {
105
+ const needsCellRender = md?.dataDomain === MetadataDataDomains.DataList || md?.dataDomain === MetadataDataDomains.UserID;
92
106
  return ([
93
- { dataField: 'value', dataType: md?.dataType === MetadataDataTypes.DateTime ? 'date' : 'string', caption: md?.nameLoc, width: 'min-content' },
107
+ { dataField: 'value', dataType: md?.dataType === MetadataDataTypes.DateTime ? 'date' : 'string', caption: md?.nameLoc, width: 'min-content', ...(needsCellRender && { cellRender: valueCellRender }) },
94
108
  { dataField: 'Count', dataType: 'number', caption: 'N°' }
95
109
  ]);
96
- }, [md]);
110
+ }, [md, valueCellRender]);
97
111
  const customSummary = useMemo(() => {
98
112
  return ({
99
113
  totalItems: [
@@ -16,6 +16,8 @@ interface ITMUserChooserProps extends ITMChooserProps {
16
16
  initialShowChooser?: boolean;
17
17
  /** Allow showing all users with toggle button */
18
18
  allowShowAllUsers?: boolean;
19
+ /** If true, uses UserListCacheService.GetAllAdminAsync() instead of GetAllAsync() */
20
+ adminMode?: boolean;
19
21
  /** Funzione per aggiornare lo stato di apertura della modale */
20
22
  updateIsModalOpen?: (isOpen: boolean) => void;
21
23
  }
@@ -30,6 +32,8 @@ interface ITMUserChooserFormProps extends ITMChooserFormProps<UserDescriptor> {
30
32
  hideShowId?: boolean;
31
33
  /** Allow showing all users with toggle button */
32
34
  allowShowAllUsers?: boolean;
35
+ /** If true, uses UserListCacheService.GetAllAdminAsync() instead of GetAllAsync() */
36
+ adminMode?: boolean;
33
37
  }
34
38
  export declare const TMUserChooserForm: React.FunctionComponent<ITMUserChooserFormProps>;
35
39
  export declare const TMUserIcon: ({ ud }: {
@@ -8,7 +8,7 @@ import TMSummary from '../editors/TMSummary';
8
8
  import TMChooserForm from '../forms/TMChooserForm';
9
9
  import TMButton from '../base/TMButton';
10
10
  import TMDataUserIdItemViewer from '../viewers/TMDataUserIdItemViewer';
11
- const TMUserChooser = ({ labelColor, titleForm, filter, readOnly = false, icon, width, dataSource, backgroundColor, openChooserBySingleClick, buttons = [], disabled = false, showBorder = true, hideRefresh = false, hideShowId = false, elementStyle, allowMultipleSelection, values, isModifiedWhen, label, placeHolder, validationItems = [], onValueChanged, showClearButton, initialShowChooser = false, allowShowAllUsers = false, updateIsModalOpen }) => {
11
+ const TMUserChooser = ({ labelColor, titleForm, filter, readOnly = false, icon, width, dataSource, backgroundColor, openChooserBySingleClick, buttons = [], disabled = false, showBorder = true, hideRefresh = false, hideShowId = false, elementStyle, allowMultipleSelection, values, isModifiedWhen, label, placeHolder, validationItems = [], onValueChanged, showClearButton, initialShowChooser = false, allowShowAllUsers = false, adminMode = false, updateIsModalOpen }) => {
12
12
  const [showChooser, setShowChooser] = useState(initialShowChooser);
13
13
  useEffect(() => {
14
14
  setShowChooser(initialShowChooser);
@@ -24,14 +24,14 @@ const TMUserChooser = ({ labelColor, titleForm, filter, readOnly = false, icon,
24
24
  updateIsModalOpen?.(true);
25
25
  }
26
26
  }, elementStyle: elementStyle, isModifiedWhen: isModifiedWhen, openEditorOnSummaryClick: openChooserBySingleClick, label: label, template: renderTemplate(), onClearClick: showClearButton ? () => { onValueChanged?.([]); } : undefined, validationItems: validationItems }), showChooser &&
27
- _jsx(TMUserChooserForm, { title: titleForm, allowMultipleSelection: allowMultipleSelection, hasShowOnlySelectedItems: true, dataSource: dataSource, filter: filter, selectedIDs: values, hideRefresh: hideRefresh, hideShowId: hideShowId, allowShowAllUsers: allowShowAllUsers, onClose: () => {
27
+ _jsx(TMUserChooserForm, { title: titleForm, allowMultipleSelection: allowMultipleSelection, hasShowOnlySelectedItems: true, dataSource: dataSource, filter: filter, selectedIDs: values, hideRefresh: hideRefresh, hideShowId: hideShowId, allowShowAllUsers: allowShowAllUsers, adminMode: adminMode, onClose: () => {
28
28
  setShowChooser(false);
29
29
  summaryInputRef.current?.focus();
30
30
  updateIsModalOpen?.(false);
31
31
  }, onChoose: (IDs) => { onValueChanged?.(IDs); } })] }));
32
32
  };
33
33
  export default TMUserChooser;
34
- export const TMUserChooserForm = ({ allowMultipleSelection, columns, hideRefresh = false, hideShowId = false, startWithShowOnlySelectedItems = true, filter, title, hasShowOnlySelectedItems, width, height, selectedIDs, dataSource, onClose, onChoose, allowShowAllUsers = false }) => {
34
+ export const TMUserChooserForm = ({ allowMultipleSelection, columns, hideRefresh = false, hideShowId = false, startWithShowOnlySelectedItems = true, filter, title, hasShowOnlySelectedItems, width, height, selectedIDs, dataSource, onClose, onChoose, allowShowAllUsers = false, adminMode = false }) => {
35
35
  const [currentDataSource, setCurrentDataSource] = useState(dataSource);
36
36
  const [showingAllUsers, setShowingAllUsers] = useState(false);
37
37
  const dataColumns = useMemo(() => {
@@ -45,8 +45,10 @@ export const TMUserChooserForm = ({ allowMultipleSelection, columns, hideRefresh
45
45
  const getItems = async (refreshCache) => {
46
46
  TMSpinner.show({ description: `${SDKUI_Localizator.Loading} - ${SDK_Localizator.Users} ...` });
47
47
  if (refreshCache)
48
- UserListCacheService.RemoveAll();
49
- let allUsers = await UserListCacheService.GetAllAsync();
48
+ adminMode ? UserListCacheService.RemoveAllAdmin() : UserListCacheService.RemoveAll();
49
+ let allUsers = adminMode
50
+ ? await UserListCacheService.GetAllAdminAsync()
51
+ : await UserListCacheService.GetAllAsync();
50
52
  let users = filter ? allUsers?.filter(filter) : allUsers;
51
53
  TMSpinner.hide();
52
54
  return users;
@@ -27,11 +27,13 @@ export declare class FormulaDescriptor {
27
27
  mid?: number;
28
28
  metadataDataTypeDest?: MetadataDataTypes;
29
29
  tid?: number;
30
+ description?: string;
30
31
  }
31
32
  export declare const renderFormulaIcon: (iconType: FormulaIconTypes, tid?: number, md?: MetadataDescriptor) => import("react/jsx-runtime").JSX.Element;
32
33
  declare const TMFormulaEditor: React.FunctionComponent<ITMApplyFormProps<FormulaDescriptor>>;
33
34
  export default TMFormulaEditor;
34
35
  export declare class FormulaHelper {
36
+ static translateDescInFormula: (text: string, returnType?: string) => string;
35
37
  static isFormula(value: string | undefined): boolean;
36
38
  static removeFormulaTag(value: string | undefined): string | undefined;
37
39
  static addFormulaTag(value: string | undefined): string | undefined;