@topconsultnpm/sdkui-react 6.20.0-dev1.6 → 6.20.0-dev1.60

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 (84) hide show
  1. package/lib/components/NewComponents/ContextMenu/TMContextMenu.d.ts +4 -0
  2. package/lib/components/NewComponents/ContextMenu/TMContextMenu.js +416 -0
  3. package/lib/components/NewComponents/ContextMenu/hooks.d.ts +13 -0
  4. package/lib/components/NewComponents/ContextMenu/hooks.js +61 -0
  5. package/lib/components/NewComponents/ContextMenu/index.d.ts +5 -0
  6. package/lib/components/NewComponents/ContextMenu/index.js +3 -0
  7. package/lib/components/NewComponents/ContextMenu/styles.d.ts +31 -0
  8. package/lib/components/NewComponents/ContextMenu/styles.js +336 -0
  9. package/lib/components/NewComponents/ContextMenu/types.d.ts +39 -0
  10. package/lib/components/NewComponents/ContextMenu/types.js +1 -0
  11. package/lib/components/NewComponents/ContextMenu/useLongPress.d.ts +21 -0
  12. package/lib/components/NewComponents/ContextMenu/useLongPress.js +112 -0
  13. package/lib/components/NewComponents/FloatingMenuBar/TMFloatingMenuBar.d.ts +4 -0
  14. package/lib/components/NewComponents/FloatingMenuBar/TMFloatingMenuBar.js +745 -0
  15. package/lib/components/NewComponents/FloatingMenuBar/index.d.ts +2 -0
  16. package/lib/components/NewComponents/FloatingMenuBar/index.js +2 -0
  17. package/lib/components/NewComponents/FloatingMenuBar/styles.d.ts +51 -0
  18. package/lib/components/NewComponents/FloatingMenuBar/styles.js +385 -0
  19. package/lib/components/NewComponents/FloatingMenuBar/types.d.ts +29 -0
  20. package/lib/components/NewComponents/FloatingMenuBar/types.js +1 -0
  21. package/lib/components/base/TMAccordionNew.js +35 -14
  22. package/lib/components/base/TMCustomButton.js +61 -17
  23. package/lib/components/base/TMDataGrid.d.ts +7 -4
  24. package/lib/components/base/TMDataGrid.js +142 -11
  25. package/lib/components/choosers/TMMetadataChooser.js +8 -1
  26. package/lib/components/editors/TMMetadataValues.js +23 -5
  27. package/lib/components/editors/TMTextBox.js +6 -3
  28. package/lib/components/features/documents/TMDcmtForm.d.ts +13 -1
  29. package/lib/components/features/documents/TMDcmtForm.js +386 -194
  30. package/lib/components/features/documents/TMDcmtPreview.js +40 -69
  31. package/lib/components/features/documents/TMMasterDetailDcmts.js +37 -52
  32. package/lib/components/features/search/TMDcmtCheckoutInfoForm.d.ts +8 -0
  33. package/lib/components/features/search/{TMSearchResultCheckoutInfoForm.js → TMDcmtCheckoutInfoForm.js} +5 -10
  34. package/lib/components/features/search/TMSavedQuerySelector.js +72 -67
  35. package/lib/components/features/search/TMSearch.js +30 -5
  36. package/lib/components/features/search/TMSearchQueryPanel.js +13 -12
  37. package/lib/components/features/search/TMSearchResult.js +57 -216
  38. package/lib/components/features/search/TMSearchResultsMenuItems.d.ts +3 -3
  39. package/lib/components/features/search/TMSearchResultsMenuItems.js +205 -169
  40. package/lib/components/features/search/TMSignSettingsForm.js +1 -1
  41. package/lib/components/features/search/TMSignatureInfoContent.d.ts +6 -0
  42. package/lib/components/features/search/TMSignatureInfoContent.js +140 -0
  43. package/lib/components/features/search/TMViewHistoryDcmt.js +1 -1
  44. package/lib/components/features/tasks/TMTaskForm.js +20 -1
  45. package/lib/components/features/tasks/TMTasksUtils.d.ts +2 -2
  46. package/lib/components/features/tasks/TMTasksUtils.js +62 -52
  47. package/lib/components/features/tasks/TMTasksView.js +6 -6
  48. package/lib/components/features/workflow/TMWorkflowPopup.d.ts +32 -2
  49. package/lib/components/features/workflow/TMWorkflowPopup.js +112 -14
  50. package/lib/components/features/workflow/diagram/WFDiagram.js +2 -2
  51. package/lib/components/forms/Login/LoginValidatorService.d.ts +2 -0
  52. package/lib/components/forms/Login/LoginValidatorService.js +7 -2
  53. package/lib/components/forms/Login/TMLoginForm.js +34 -6
  54. package/lib/components/forms/TMChooserForm.js +1 -1
  55. package/lib/components/grids/TMBlogsPost.js +55 -30
  56. package/lib/components/index.d.ts +2 -0
  57. package/lib/components/index.js +2 -0
  58. package/lib/components/viewers/TMDataListItemViewer.d.ts +2 -1
  59. package/lib/components/viewers/TMDataListItemViewer.js +12 -11
  60. package/lib/css/tm-sdkui.css +1 -1
  61. package/lib/helper/SDKUI_Globals.d.ts +17 -0
  62. package/lib/helper/SDKUI_Globals.js +9 -0
  63. package/lib/helper/SDKUI_Localizator.d.ts +9 -1
  64. package/lib/helper/SDKUI_Localizator.js +87 -1
  65. package/lib/helper/TMIcons.d.ts +2 -0
  66. package/lib/helper/TMIcons.js +6 -0
  67. package/lib/helper/TMPdfViewer.d.ts +8 -0
  68. package/lib/helper/TMPdfViewer.js +368 -0
  69. package/lib/helper/checkinCheckoutManager.d.ts +32 -2
  70. package/lib/helper/checkinCheckoutManager.js +115 -38
  71. package/lib/helper/devextremeCustomMessages.d.ts +30 -0
  72. package/lib/helper/devextremeCustomMessages.js +30 -0
  73. package/lib/helper/helpers.d.ts +2 -1
  74. package/lib/helper/helpers.js +14 -3
  75. package/lib/helper/index.d.ts +1 -0
  76. package/lib/helper/index.js +1 -0
  77. package/lib/helper/queryHelper.js +29 -0
  78. package/lib/hooks/useCheckInOutOperations.d.ts +28 -0
  79. package/lib/hooks/useCheckInOutOperations.js +223 -0
  80. package/lib/hooks/useWorkflowApprove.d.ts +4 -0
  81. package/lib/hooks/useWorkflowApprove.js +14 -1
  82. package/lib/ts/types.d.ts +56 -1
  83. package/package.json +5 -2
  84. package/lib/components/features/search/TMSearchResultCheckoutInfoForm.d.ts +0 -8
@@ -4,31 +4,68 @@ import TMModal from './TMModal';
4
4
  import styled from 'styled-components';
5
5
  import { SDKUI_Localizator, TMLayoutWaitingContainer } from '../..';
6
6
  import { getButtonAttributes, getSelectedItem } from '../../helper/dcmtsHelper';
7
+ import { DeviceType, useDeviceType } from './TMDeviceProvider';
7
8
  const IframeContainer = styled.div `
8
9
  display: flex;
9
10
  height: 100%;
10
11
  flex-direction: column;
11
- padding-left: 15px;
12
+ position: relative;
12
13
  `;
13
14
  const StyledIframe = styled.iframe `
14
15
  border: none;
15
16
  flex: 1;
16
17
  `;
18
+ const LoadingOverlay = styled.div `
19
+ position: absolute;
20
+ top: 0;
21
+ left: 0;
22
+ right: 0;
23
+ bottom: 0;
24
+ background-color: rgba(128, 128, 128, 0.3);
25
+ display: flex;
26
+ align-items: center;
27
+ justify-content: center;
28
+ z-index: 1000;
29
+
30
+ &::after {
31
+ content: '';
32
+ width: 40px;
33
+ height: 40px;
34
+ border: 4px solid rgba(255, 255, 255, 0.3);
35
+ border-top-color: #fff;
36
+ border-radius: 50%;
37
+ animation: spin 0.8s linear infinite;
38
+ }
39
+
40
+ @keyframes spin {
41
+ to {
42
+ transform: rotate(360deg);
43
+ }
44
+ }
45
+ `;
17
46
  const TMCustomButton = (props) => {
18
47
  const { button, isModal = true, formData, selectedItems, onClose } = props;
19
48
  const { appName: scriptUrl, arguments: args } = button;
49
+ const Device = useDeviceType();
20
50
  const iframeRef = useRef(null);
21
51
  const attributes = useMemo(() => getButtonAttributes(args, formData, selectedItems), [args, formData, selectedItems]);
22
52
  const RunOnce = button.mode === "RunOnce";
23
53
  const [loading, setLoading] = useState(true);
24
54
  const [error, setError] = useState(false);
25
- const selectedItemsCount = selectedItems?.length || 0;
55
+ const itemsToProcess = useMemo(() => selectedItems && selectedItems.length > 0 ? selectedItems : [attributes], [selectedItems, attributes]);
26
56
  // Stati per il wait panel
27
- const [showWaitPanel, setShowWaitPanel] = useState(selectedItemsCount > 0 && !RunOnce);
28
- const [waitPanelText, setWaitPanelText] = useState(SDKUI_Localizator.CustomButtonActions.replaceParams(1, selectedItemsCount));
57
+ const [showWaitPanel, setShowWaitPanel] = useState(itemsToProcess.length > 0 && !RunOnce);
58
+ const [waitPanelText, setWaitPanelText] = useState(SDKUI_Localizator.CustomButtonActions.replaceParams(1, itemsToProcess.length));
29
59
  const [waitPanelValue, setWaitPanelValue] = useState(0);
30
- const [waitPanelMaxValue, setWaitPanelMaxValue] = useState(selectedItemsCount);
60
+ const [waitPanelMaxValue, setWaitPanelMaxValue] = useState(itemsToProcess.length);
31
61
  const [abortController, setAbortController] = useState(undefined);
62
+ // Aggiungi timestamp all'URL per evitare cache
63
+ const iframeUrl = useMemo(() => {
64
+ if (!scriptUrl)
65
+ return '';
66
+ const separator = scriptUrl.includes('?') ? '&' : '?';
67
+ return `${scriptUrl}${separator}t=${Date.now()}`;
68
+ }, [scriptUrl]);
32
69
  const targetOrigin = useMemo(() => {
33
70
  if (!scriptUrl)
34
71
  return '*';
@@ -41,26 +78,35 @@ const TMCustomButton = (props) => {
41
78
  }
42
79
  }, [scriptUrl]);
43
80
  const handleLoad = () => setLoading(false);
81
+ const isMobile = Device === DeviceType.MOBILE;
44
82
  const handleError = () => {
45
83
  setLoading(false);
46
84
  setError(true);
47
85
  };
48
86
  const executeSequentially = async (controller) => {
49
- if (!selectedItems)
87
+ if (!itemsToProcess)
50
88
  return;
51
- for (const [index, item] of selectedItems.entries()) {
89
+ for (const [index, item] of itemsToProcess.entries()) {
52
90
  if (controller.signal.aborted)
53
91
  break;
54
- setWaitPanelText(SDKUI_Localizator.CustomButtonActions.replaceParams(index + 1, selectedItemsCount));
92
+ setWaitPanelText(SDKUI_Localizator.CustomButtonActions.replaceParams(index + 1, itemsToProcess.length));
55
93
  setWaitPanelValue(index);
56
94
  // Attendi che l'iframe sia pronto e invia il messaggio
57
95
  await new Promise((resolve) => {
58
96
  const checkIframe = setInterval(() => {
59
97
  if (iframeRef.current?.contentWindow) {
60
98
  clearInterval(checkIframe);
61
- //devo convertire item in formData
62
- const processedItem = getSelectedItem(args, formData, item);
63
- postMessageIframe(processedItem);
99
+ if (selectedItems && selectedItems.length > 0) {
100
+ //devo convertire item in formData
101
+ const processedItem = getSelectedItem(args, formData, item);
102
+ postMessageIframe(processedItem);
103
+ }
104
+ else {
105
+ postMessageIframe(item);
106
+ }
107
+ //imposta 100% se sono all'ultimo item
108
+ if (index === itemsToProcess.length - 1)
109
+ setWaitPanelValue(index + 1);
64
110
  // Attendi prima di passare al prossimo
65
111
  setTimeout(() => {
66
112
  setWaitPanelValue(index + 1);
@@ -82,8 +128,7 @@ const TMCustomButton = (props) => {
82
128
  useEffect(() => {
83
129
  if (loading || error)
84
130
  return;
85
- //if(error) clearTimeout(timeoutIframe);
86
- if (!RunOnce && selectedItemsCount > 0) {
131
+ if (!RunOnce && itemsToProcess.length > 0) {
87
132
  // esegui per ogni item selezionato
88
133
  const controller = new AbortController();
89
134
  controller.signal.addEventListener('abort', () => {
@@ -91,7 +136,7 @@ const TMCustomButton = (props) => {
91
136
  onClose?.();
92
137
  });
93
138
  setAbortController(controller);
94
- setWaitPanelMaxValue(selectedItemsCount);
139
+ setWaitPanelMaxValue(itemsToProcess.length);
95
140
  executeSequentially(controller);
96
141
  }
97
142
  else {
@@ -103,7 +148,6 @@ const TMCustomButton = (props) => {
103
148
  onClose?.();
104
149
  }, 2000);
105
150
  }
106
- //clearTimeout(timeoutIframe);
107
151
  }
108
152
  }, [loading, error, RunOnce]);
109
153
  useEffect(() => {
@@ -112,7 +156,7 @@ const TMCustomButton = (props) => {
112
156
  onClose?.();
113
157
  }
114
158
  }, []);
115
- const iframeContent = (_jsxs(IframeContainer, { style: !RunOnce ? { visibility: 'hidden' } : {}, children: [error && _jsx("div", { children: "Si \u00E8 verificato un errore nel caricamento del contenuto." }), !error && _jsx(StyledIframe, { ref: iframeRef, loading: 'lazy', onLoad: handleLoad, onError: handleError, src: scriptUrl })] }));
116
- return isModal && RunOnce ? (_jsx(TMModal, { title: button.title, width: '60%', height: '70%', resizable: true, expandable: true, onClose: onClose, children: iframeContent })) : !RunOnce && (_jsxs(_Fragment, { children: [_jsx(TMLayoutWaitingContainer, { showWaitPanel: showWaitPanel, waitPanelTitle: SDKUI_Localizator.CustomButtonAction, showWaitPanelPrimary: true, waitPanelTextPrimary: waitPanelText, waitPanelValuePrimary: waitPanelValue, waitPanelMaxValuePrimary: waitPanelMaxValue, showWaitPanelSecondary: false, isCancelable: true, abortController: abortController, children: undefined }), iframeContent] }));
159
+ const iframeContent = (_jsxs(IframeContainer, { style: !RunOnce ? { visibility: 'hidden' } : {}, children: [loading && _jsx(LoadingOverlay, {}), error && _jsx("div", { children: "Si \u00E8 verificato un errore nel caricamento del contenuto." }), !error && _jsx(StyledIframe, { ref: iframeRef, loading: 'lazy', onLoad: handleLoad, onError: handleError, src: iframeUrl })] }));
160
+ return isModal && RunOnce ? (_jsx(TMModal, { title: button.title, width: isMobile ? '95%' : '60%', height: isMobile ? '95%' : '70%', resizable: isMobile ? false : true, expandable: isMobile ? false : true, onClose: onClose, children: iframeContent })) : !RunOnce && (_jsxs(_Fragment, { children: [_jsx(TMLayoutWaitingContainer, { showWaitPanel: showWaitPanel, waitPanelTitle: SDKUI_Localizator.CustomButtonAction, showWaitPanelPrimary: true, waitPanelTextPrimary: waitPanelText, waitPanelValuePrimary: waitPanelValue, waitPanelMaxValuePrimary: waitPanelMaxValue, showWaitPanelSecondary: false, isCancelable: true, abortController: abortController, children: undefined }), iframeContent] }));
117
161
  };
118
162
  export default TMCustomButton;
@@ -2,6 +2,7 @@ import React from 'react';
2
2
  import { IColumnProps, IDataGridOptions, IMasterDetailProps } from 'devextreme-react/data-grid';
3
3
  import dxDataGrid from 'devextreme/ui/data_grid';
4
4
  import { ITMCounterContainerProps } from './TMCounterContainer';
5
+ import { TMContextMenuItemProps } from '../NewComponents/ContextMenu/types';
5
6
  export interface TMDataGridContextMenuItem {
6
7
  text: string;
7
8
  icon: string;
@@ -31,16 +32,16 @@ export interface TMDataGridProps<T> extends IDataGridOptions {
31
32
  pageSize?: TMDataGridPageSize;
32
33
  /** Configures the search panel position in the toolbar */
33
34
  searchPanelToolbarPosition?: 'before' | 'default';
34
- /** if visible, set focus on SearchPanel */
35
- searchPanelFocusStarting?: boolean;
35
+ /** Trigger to set focus on SearchPanel (only if visible) - change the number to trigger focus */
36
+ searchPanelFocusTrigger?: number;
36
37
  /** Show the header filter */
37
38
  showHeaderFilter?: boolean;
38
39
  /** Show the filter panel */
39
40
  showFilterPanel?: boolean;
40
41
  /** Show the load panel */
41
42
  showLoadPanel?: boolean;
42
- /** Show the column chooser */
43
- showColumnChooser?: boolean;
43
+ /** Show the header column chooser in context menu */
44
+ showHeaderColumnChooser?: boolean;
44
45
  /** Show the search panel */
45
46
  showSearchPanel?: boolean;
46
47
  /** Show the group panel */
@@ -51,6 +52,8 @@ export interface TMDataGridProps<T> extends IDataGridOptions {
51
52
  masterDetail?: IMasterDetailProps;
52
53
  /** On Has Filters Change */
53
54
  onHasFiltersChange?: (hasFilters: boolean) => void;
55
+ /** Custom context menu items - when provided, replaces DevExtreme's native context menu with TMContextMenu */
56
+ customContextMenuItems?: TMContextMenuItemProps[];
54
57
  }
55
58
  declare const TMDataGrid: React.ForwardRefExoticComponent<TMDataGridProps<unknown> & React.RefAttributes<dxDataGrid<any, any>>>;
56
59
  export default TMDataGrid;
@@ -1,9 +1,11 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import React, { useCallback, useEffect, useImperativeHandle, useRef, useState } from 'react';
3
- import DataGrid, { Column, HeaderFilter, Selection, Scrolling, LoadPanel, SearchPanel, Pager, Sorting, Paging, FilterPanel, ColumnChooser, Grouping, GroupPanel, Summary, Editing, FilterRow, StateStoring, RowDragging, MasterDetail } from 'devextreme-react/data-grid';
3
+ import DataGrid, { Column, HeaderFilter, Selection, Scrolling, LoadPanel, SearchPanel, Pager, Sorting, Paging, FilterPanel, ColumnChooser, Grouping, GroupPanel, Summary, Editing, FilterRow, StateStoring, RowDragging, MasterDetail, Position, ColumnChooserSearch, ColumnChooserSelection } from 'devextreme-react/data-grid';
4
4
  import DataSource from 'devextreme/data/data_source';
5
5
  import { IconAll, IconSelected, IconVisible, SDKUI_Globals, SDKUI_Localizator } from '../../helper';
6
6
  import TMCounterContainer, { CounterItemKey } from './TMCounterContainer';
7
+ import TMContextMenu from '../NewComponents/ContextMenu/TMContextMenu';
8
+ import { useLongPress } from '../NewComponents/ContextMenu/useLongPress';
7
9
  ;
8
10
  export var TMDataGridPageSize;
9
11
  (function (TMDataGridPageSize) {
@@ -16,9 +18,9 @@ const TMDataGrid = React.forwardRef((props, ref) => {
16
18
  // main properties
17
19
  keyExpr = 'id', dataSource, focusedRowEnabled = true, hoverStateEnabled = true, focusedRowKey, selectedRowKeys = [],
18
20
  // custom options
19
- dataColumns = [], pageSize = TMDataGridPageSize.Large, showHeaderFilter = true, showFilterPanel = true, showLoadPanel = true, showSearchPanel = true, searchPanelToolbarPosition = 'before', searchPanelFocusStarting = false, counterConfig = { show: false, items: new Map() }, onHasFiltersChange,
21
+ dataColumns = [], pageSize = TMDataGridPageSize.Large, showHeaderFilter = true, showFilterPanel = true, showHeaderColumnChooser = false, showLoadPanel = true, showSearchPanel = true, searchPanelToolbarPosition = 'before', searchPanelFocusTrigger = 0, counterConfig = { show: false, items: new Map() }, onHasFiltersChange, customContextMenuItems,
20
22
  // events and callbacks
21
- 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, columnChooser, grouping, groupPanel, filterRow, headerFilter, editing, rowDragging, masterDetail,
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,
22
24
  // other properties
23
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,
24
26
  // styles
@@ -29,10 +31,82 @@ const TMDataGrid = React.forwardRef((props, ref) => {
29
31
  const [totalRecordCount, setTotalRecordCount] = useState(0);
30
32
  const [visibleItemsCount, setVisibleItemsCount] = useState(0);
31
33
  const [hasFilters, setHasFilters] = useState(false);
34
+ // Custom context menu states
35
+ const [customContextMenuVisible, setCustomContextMenuVisible] = useState(false);
36
+ const [customContextMenuPosition, setCustomContextMenuPosition] = useState({ x: 0, y: 0 });
37
+ const [customContextMenuRowKey, setCustomContextMenuRowKey] = useState(undefined);
38
+ const gridContainerRef = useRef(null);
32
39
  useEffect(() => {
33
40
  const count = getRecordCount(dataSource);
34
41
  setTotalRecordCount(count);
35
42
  }, [dataSource]);
43
+ // Handle search panel focus when trigger changes
44
+ useEffect(() => {
45
+ if (!searchPanelFocusTrigger || searchPanelFocusTrigger <= 0 || !showSearchPanel || !internalRef.current)
46
+ return;
47
+ setTimeout(() => {
48
+ const searchInput = internalRef.current?.instance().element().querySelector('.dx-datagrid-search-panel input');
49
+ if (searchInput) {
50
+ searchInput.focus();
51
+ }
52
+ }, 100);
53
+ }, [searchPanelFocusTrigger, showSearchPanel]);
54
+ // Handle custom context menu (only when customContextMenuItems is provided)
55
+ useEffect(() => {
56
+ if (!customContextMenuItems || !gridContainerRef.current)
57
+ return;
58
+ const gridContainer = gridContainerRef.current;
59
+ const handleContextMenu = (e) => {
60
+ e.preventDefault();
61
+ e.stopPropagation();
62
+ // Get the clicked row
63
+ const target = e.target;
64
+ const rowElement = target.closest('.dx-data-row');
65
+ if (rowElement && internalRef.current) {
66
+ const rowIndex = Array.from(rowElement.parentElement?.children || []).indexOf(rowElement);
67
+ const rowKey = internalRef.current.instance().getKeyByRowIndex(rowIndex);
68
+ // Change focused row
69
+ internalRef.current.instance().option('focusedRowKey', rowKey);
70
+ // Show custom context menu
71
+ setCustomContextMenuVisible(true);
72
+ setCustomContextMenuPosition({ x: e.clientX, y: e.clientY });
73
+ setCustomContextMenuRowKey(rowKey);
74
+ }
75
+ };
76
+ gridContainer.addEventListener('contextmenu', handleContextMenu);
77
+ return () => {
78
+ gridContainer.removeEventListener('contextmenu', handleContextMenu);
79
+ };
80
+ }, [customContextMenuItems]);
81
+ // iOS-specific: Handle touch for focused row change and long-press for context menu
82
+ useLongPress({
83
+ containerRef: gridContainerRef,
84
+ targetSelector: '.dx-data-row',
85
+ enabled: !!customContextMenuItems,
86
+ onTouchStart: ({ rowElement }) => {
87
+ // Change focused row immediately on touch (fixes focus issue)
88
+ if (!internalRef.current)
89
+ return;
90
+ const rowIndex = Array.from(rowElement.parentElement?.children || []).indexOf(rowElement);
91
+ const rowKey = internalRef.current.instance().getKeyByRowIndex(rowIndex);
92
+ if (rowKey !== undefined && rowKey !== focusedRowKey) {
93
+ internalRef.current.instance().option('focusedRowKey', rowKey);
94
+ }
95
+ },
96
+ onLongPress: ({ clientX, clientY, target }) => {
97
+ if (!internalRef.current)
98
+ return;
99
+ const rowElement = target.closest('.dx-data-row');
100
+ if (!rowElement)
101
+ return;
102
+ const rowIndex = Array.from(rowElement.parentElement?.children || []).indexOf(rowElement);
103
+ const rowKey = internalRef.current.instance().getKeyByRowIndex(rowIndex);
104
+ // Show context menu
105
+ setCustomContextMenuVisible(true);
106
+ setCustomContextMenuPosition({ x: clientX, y: clientY });
107
+ setCustomContextMenuRowKey(rowKey);
108
+ },
109
+ });
36
110
  // Creating a ref to store the timestamp of the last selection change
37
111
  const lastSelectionChangeTime = useRef(Date.now());
38
112
  useEffect(() => {
@@ -101,6 +175,8 @@ const TMDataGrid = React.forwardRef((props, ref) => {
101
175
  }
102
176
  return {
103
177
  ...item,
178
+ // Ensure icon is not null/undefined to prevent DevExtreme errors
179
+ icon: item.icon || '',
104
180
  disabled: disabled || disabledCalculation, // An item is disabled if it's explicitly set to `true` or if the calculation above determines so
105
181
  // Define the behavior when the menu item is clicked
106
182
  onClick: () => {
@@ -132,10 +208,51 @@ const TMDataGrid = React.forwardRef((props, ref) => {
132
208
  };
133
209
  });
134
210
  }, [focusedRowEnabled, focusedRowKey, selectedRowKeys]);
211
+ // Process custom context menu items (for TMContextMenuItemProps)
212
+ const processCustomContextMenuItems = useCallback((items, rowID) => {
213
+ return items.map(item => {
214
+ let disabled = item.disabled ?? false;
215
+ let disabledCalculation = false;
216
+ const id = focusedRowEnabled ? focusedRowKey : rowID;
217
+ if (item.operationType === 'singleRow') {
218
+ disabledCalculation = selectedRowKeys.length > 1 || id === undefined;
219
+ }
220
+ if (item.operationType === 'multiRow') {
221
+ disabledCalculation = selectedRowKeys.length === 0 && id === undefined;
222
+ }
223
+ const originalOnClick = item.onClick;
224
+ return {
225
+ ...item,
226
+ disabled: disabled || disabledCalculation,
227
+ onClick: originalOnClick ? () => {
228
+ if (item.operationType === 'singleRow' && id !== undefined) {
229
+ originalOnClick(id);
230
+ }
231
+ else if (item.operationType === 'multiRow' && id !== undefined) {
232
+ if (selectedRowKeys.length > 0) {
233
+ originalOnClick(selectedRowKeys);
234
+ }
235
+ else {
236
+ originalOnClick([id]);
237
+ }
238
+ }
239
+ else {
240
+ originalOnClick();
241
+ }
242
+ } : undefined,
243
+ submenu: item.submenu ? processCustomContextMenuItems(item.submenu, id) : undefined,
244
+ };
245
+ });
246
+ }, [focusedRowEnabled, focusedRowKey, selectedRowKeys]);
135
247
  // Handle context menu preparation
136
248
  const onContextMenuPreparingCallback = useCallback((e) => {
137
249
  if (e === undefined)
138
250
  return;
251
+ // If custom context menu is enabled, completely disable DevExtreme's native context menu
252
+ if (customContextMenuItems && e.target === 'content') {
253
+ e.items = undefined;
254
+ return;
255
+ }
139
256
  if (onContextMenuPreparing)
140
257
  onContextMenuPreparing(e);
141
258
  if (e.target === 'content') {
@@ -146,7 +263,18 @@ const TMDataGrid = React.forwardRef((props, ref) => {
146
263
  e.items = [...updatedContextMenuItems];
147
264
  }
148
265
  }
149
- }, [updateContextMenuItems, onContextMenuPreparing]);
266
+ // Add column chooser to header context menu
267
+ if (e.target === 'header' && showHeaderColumnChooser) {
268
+ e.items = e.items || [];
269
+ e.items.push({
270
+ text: SDKUI_Localizator.ShowColumnSelection,
271
+ icon: 'columnchooser',
272
+ onItemClick: () => {
273
+ internalRef.current?.instance().showColumnChooser();
274
+ }
275
+ });
276
+ }
277
+ }, [updateContextMenuItems, onContextMenuPreparing, showHeaderColumnChooser, customContextMenuItems]);
150
278
  // Handle toolbar preparation, especially for the search panel
151
279
  const onToolbarPreparingCallback = useCallback((e) => {
152
280
  if (e === undefined || e.toolbarOptions === undefined || e.toolbarOptions.items === undefined)
@@ -171,10 +299,9 @@ const TMDataGrid = React.forwardRef((props, ref) => {
171
299
  return;
172
300
  // Update state with the current number of visible rows in the DataGrid
173
301
  setVisibleItemsCount(internalRef.current.instance()?.getVisibleRows()?.length ?? 0);
174
- // Focusing SearchPanel
175
- if (showSearchPanel && searchPanelFocusStarting) {
302
+ // Focusing SearchPanel on content ready
303
+ if (showSearchPanel && searchPanelFocusTrigger && searchPanelFocusTrigger > 0) {
176
304
  // Use a small delay to ensure the DOM is fully rendered before trying to focus
177
- // This can prevent issues with the focus not being set correctly
178
305
  setTimeout(() => {
179
306
  const searchInput = internalRef.current?.instance().element().querySelector('.dx-datagrid-search-panel input');
180
307
  if (searchInput) {
@@ -182,7 +309,7 @@ const TMDataGrid = React.forwardRef((props, ref) => {
182
309
  }
183
310
  }, 100);
184
311
  }
185
- }, [onContentReady]);
312
+ }, [onContentReady, showSearchPanel, searchPanelFocusTrigger]);
186
313
  const onOptionChangedCallback = useCallback((e) => {
187
314
  // Assicurati che component esista
188
315
  const grid = e.component;
@@ -215,15 +342,19 @@ const TMDataGrid = React.forwardRef((props, ref) => {
215
342
  // Propaga l'evento originale
216
343
  onOptionChanged?.(e);
217
344
  }, [onOptionChanged, onHasFiltersChange]);
218
- return _jsxs("div", { style: { width: "100%", height: "100%" }, children: [_jsx("div", { style: { width: "100%", height: counterConfig.show ? "calc(100% - 25px)" : "100%" }, children: _jsxs(DataGrid, { ref: internalRef, id: id, className: `tm-datagrid ${hasFilters ? 'has-filters' : ''}`,
345
+ return _jsxs("div", { style: { width: "100%", height: "100%" }, children: [_jsx("div", { ref: gridContainerRef, style: { width: "100%", height: counterConfig.show ? "calc(100% - 25px)" : "100%" }, children: _jsxs(DataGrid, { ref: internalRef, id: id, className: `tm-datagrid ${hasFilters ? 'has-filters' : ''}`,
219
346
  // main properties
220
347
  keyExpr: keyExpr, dataSource: dataSource, selectedRowKeys: selectedRowKeys, focusedRowEnabled: focusedRowEnabled, hoverStateEnabled: hoverStateEnabled,
221
348
  // events and callbacks
222
- 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,
349
+ onSelectionChanged: onSelectionChangedCallback, onRowDblClick: onRowDblClickCallback, onRowPrepared: onRowPrepared, onContextMenuPreparing: customContextMenuItems ? undefined : 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,
223
350
  // other properties
224
351
  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,
225
352
  // styles
226
- width: width, height: height, style: { userSelect: 'none' }, children: [dataColumns.map((column, index) => (_jsx(Column, { ...column }, column.caption + index.toString()))), sorting && _jsx(Sorting, { ...sorting }), selection && _jsx(Selection, { ...selection }), scrolling && _jsx(Scrolling, { ...scrolling }), summary && _jsx(Summary, { ...summary }), showHeaderFilter && _jsx(HeaderFilter, { visible: true, ...headerFilter }), rowDragging && _jsx(RowDragging, { ...rowDragging }), filterRow && _jsx(FilterRow, { ...filterRow }), showFilterPanel && _jsx(FilterPanel, { visible: true }), columnChooser && _jsx(ColumnChooser, { ...columnChooser }), stateStoring && _jsx(StateStoring, { ...stateStoring }), groupPanel && _jsx(GroupPanel, { ...groupPanel }), _jsx(Grouping, { contextMenuEnabled: true, ...grouping }), _jsx(LoadPanel, { enabled: showLoadPanel }), _jsx(SearchPanel, { visible: showSearchPanel, searchVisibleColumnsOnly: true, highlightSearchText: true }), editing && _jsx(Editing, { ...editing }), paging && _jsx(Paging, { ...paging }), pager && _jsx(Pager, { ...pager, visible: totalRecordCount > pageSize }), masterDetail && _jsx(MasterDetail, { ...masterDetail })] }) }), counterConfig.show && _jsx("div", { style: { width: "100%", height: "25px", display: "flex", alignItems: "center", gap: "15px", backgroundColor: "#e0e0e0" }, children: _jsx(TMCounterContainer, { items: counterValues, bgColorContainer: counterConfig.bgColorContainer, bgColorItem: counterConfig.bgColorItem, hoverColorItem: counterConfig.hoverColorItem, textColorItem: counterConfig.textColorItem }) })] });
353
+ width: width, height: height, style: { userSelect: 'none' }, children: [dataColumns.map((column, index) => (_jsx(Column, { ...column }, column.caption + index.toString()))), sorting && _jsx(Sorting, { ...sorting }), selection && _jsx(Selection, { ...selection }), scrolling && _jsx(Scrolling, { ...scrolling }), summary && _jsx(Summary, { ...summary }), showHeaderFilter && _jsx(HeaderFilter, { visible: true, ...headerFilter }), rowDragging && _jsx(RowDragging, { ...rowDragging }), filterRow && _jsx(FilterRow, { ...filterRow }), showFilterPanel && _jsx(FilterPanel, { visible: true }), showHeaderColumnChooser && _jsxs(ColumnChooser, { height: "400px", enabled: !showHeaderColumnChooser, mode: "select", children: [_jsx(Position, { my: "center", at: "center", of: window }), _jsx(ColumnChooserSearch, { enabled: true }), _jsx(ColumnChooserSelection, { allowSelectAll: false, selectByClick: true, recursive: true })] }), stateStoring && _jsx(StateStoring, { ...stateStoring }), groupPanel && _jsx(GroupPanel, { ...groupPanel }), _jsx(Grouping, { contextMenuEnabled: true, ...grouping }), _jsx(LoadPanel, { enabled: showLoadPanel }), _jsx(SearchPanel, { visible: showSearchPanel, searchVisibleColumnsOnly: true, highlightSearchText: true }), editing && _jsx(Editing, { ...editing }), paging && _jsx(Paging, { ...paging }), pager && _jsx(Pager, { ...pager, visible: totalRecordCount > pageSize }), masterDetail && _jsx(MasterDetail, { ...masterDetail })] }) }), counterConfig.show && _jsx("div", { style: { width: "100%", height: "25px", display: "flex", alignItems: "center", gap: "15px", backgroundColor: "#e0e0e0" }, children: _jsx(TMCounterContainer, { items: counterValues, bgColorContainer: counterConfig.bgColorContainer, bgColorItem: counterConfig.bgColorItem, hoverColorItem: counterConfig.hoverColorItem, textColorItem: counterConfig.textColorItem }) }), customContextMenuItems && (_jsx(TMContextMenu, { target: ".dx-data-row", items: processCustomContextMenuItems(customContextMenuItems, customContextMenuRowKey), externalControl: {
354
+ visible: customContextMenuVisible,
355
+ position: customContextMenuPosition,
356
+ onClose: () => setCustomContextMenuVisible(false)
357
+ } }))] });
227
358
  });
228
359
  export default TMDataGrid;
229
360
  const getRecordCount = (dataSource) => {
@@ -13,8 +13,15 @@ import TMChooserForm from '../forms/TMChooserForm';
13
13
  import TMSpinner from '../base/TMSpinner';
14
14
  const TMMetadataChooser = ({ tmSession, dataSource, showEditButton = true, buttons = [], disabled, validationItems, getColorIndex, showCompleteMetadataName, qdShowOnlySelectItems, borderRadius = '4px', fontSize = FontSize.defaultFontSize, backgroundColor, openEditorOnSummaryClick, showBorder = true, showId = false, elementStyle, allowMultipleSelection, allowSysMetadata, showSysMetadataDirectly, value, values, isModifiedWhen, tids, label, width, height, showClearButton, qd, placeHolder, filterMetadata, onValueChanged }) => {
15
15
  const [showChooser, setShowChooser] = useState(false);
16
+ const getinputMd = () => {
17
+ if (values && values.length > 0 && values[0].mid && values[0].mid < 0) {
18
+ let md = dataSource?.find((md) => md.id === values[0].mid);
19
+ return md;
20
+ }
21
+ return undefined;
22
+ };
16
23
  const renderTemplate = useMemo(() => {
17
- return (_jsxs(StyledDivHorizontal, { style: { width: 'max-content', height: '100%' }, children: [values && _jsx(TMMidViewer, { tmSession: tmSession, tid_mid: values[0], showIcon: true, showId: showId, showCompleteName: showCompleteMetadataName }), values && values.length > 1 && _jsx("p", { style: { marginLeft: '10px' }, children: `(+${values.length - 1} ${values.length == 2 ? 'altro' : 'altri'})` }), (values == undefined || values.length == 0) && _jsx("p", { children: placeHolder })] }));
24
+ return (_jsxs(StyledDivHorizontal, { style: { width: 'max-content', height: '100%' }, children: [values && values.length > 0 && values[0].mid && values[0].mid > 0 && _jsx(TMMidViewer, { tmSession: tmSession, tid_mid: values[0], showIcon: true, showId: showId, showCompleteName: showCompleteMetadataName }), values && values.length > 0 && values[0].mid && values[0].mid < 0 && _jsx(TMMidViewer, { tmSession: tmSession, tid_mid: values[0], inputMd: getinputMd(), showIcon: true, showId: showId, showCompleteName: showCompleteMetadataName }), values && values.length > 1 && _jsx("p", { style: { marginLeft: '10px' }, children: `(+${values.length - 1} ${values.length == 2 ? 'altro' : 'altri'})` }), (values == undefined || values.length == 0) && _jsx("p", { children: placeHolder })] }));
18
25
  }, [values, tmSession, showId, showCompleteMetadataName, placeHolder]);
19
26
  return (_jsxs(_Fragment, { children: [_jsx(TMSummary, { label: label, width: width, height: height, disabled: disabled, validationItems: validationItems, backgroundColor: backgroundColor, buttons: buttons, placeHolder: placeHolder, fontSize: fontSize, showBorder: showBorder, borderRadius: borderRadius, hasValue: values && values.length > 0, showClearButton: showClearButton, showEditButton: showEditButton, iconEditButton: _jsx(IconSearch, { fontSize: 16 }), openEditorOnSummaryClick: openEditorOnSummaryClick, onEditorClick: () => !disabled && setShowChooser(true), elementStyle: elementStyle, isModifiedWhen: isModifiedWhen, template: renderTemplate, onClearClick: showClearButton ? () => { onValueChanged?.([]); } : undefined }), showChooser &&
20
27
  _jsx(TMMetadataChooserForm, { tmSession: tmSession, allowMultipleSelection: allowMultipleSelection, height: '500px', width: '600px', allowSysMetadata: allowSysMetadata, showSysMetadataDirectly: showSysMetadataDirectly, getColorIndex: getColorIndex, dataSource: dataSource, tids: tids, qd: qd, qdShowOnlySelectItems: qdShowOnlySelectItems, filterMetadata: filterMetadata, selectedIDs: values, onClose: () => setShowChooser(false), onChoose: (tid_mids) => { onValueChanged?.(tid_mids); } })] }));
@@ -1,8 +1,8 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import React, { useCallback, useEffect, useMemo, useState } from "react";
3
3
  import styled from "styled-components";
4
- import { AccessLevels, DcmtTypeListCacheService, LayoutGroupBorderStyles, LayoutGroupOrientations, LayoutItemTypes, LayoutModes, MetadataDataDomains, MetadataDataTypes, SDK_Globals, SystemMIDsAsNumber, SystemTIDs, TemplateTIDs, WorkItemMetadataNames } from '@topconsultnpm/sdk-ts';
5
- import { IconUndo, IconPencil, IconFunction, IconMenuVertical, IconDataList, SDKUI_Localizator, IconNull, stringIsNullOrEmpty, deepCompare, SDKUI_Globals, IconDcmtTypeSys } from "../../helper";
4
+ import { AccessLevels, DcmtTypeListCacheService, LayoutGroupBorderStyles, LayoutGroupOrientations, LayoutItemTypes, LayoutModes, MetadataDataDomains, MetadataDataTypes, SDK_Globals, SystemMIDsAsNumber, SystemTIDs, WorkItemMetadataNames } from '@topconsultnpm/sdk-ts';
5
+ import { IconUndo, IconPencil, IconFunction, IconMenuVertical, IconDataList, SDKUI_Localizator, IconNull, stringIsNullOrEmpty, deepCompare, SDKUI_Globals, IconDcmtTypeSys, isApprovalWorkflowView } from "../../helper";
6
6
  import { TMColors } from "../../utils/theme";
7
7
  import TMButton from "../base/TMButton";
8
8
  import TMDropDownMenu from "../base/TMDropDownMenu";
@@ -389,17 +389,35 @@ const TMMetadataValues = ({ showCheckBoxes = ShowCheckBoxesMode.Never, checkPerm
389
389
  return (_jsxs("div", { style: { width: '100%' }, children: [draftData.length > 0 && _jsx(TMAccordion, { title: SDKUI_Localizator.Draft, children: draftData.map(item => renderMetadataItem(item, isReadOnly)) }), checkOutData.length > 0 && _jsx(TMAccordion, { title: `${SDKUI_Localizator.CheckIn}/${SDKUI_Localizator.CheckOut}`, children: checkOutData.map(item => renderMetadataItem(item, true)) })] }));
390
390
  }, [metadataValues, showCheckBoxes, showNullValueCheckBoxes, isReadOnly, dynDataListsToBeRefreshed, validationItems, selectedMID, isOpenDistinctValues, openChooserBySingleClick, metadataValuesOrig]);
391
391
  const layoutChronology = useMemo(() => {
392
- const chronologyData = [];
392
+ // Definiamo l'ordine desiderato: Version, Tipo, Dimensione, Autore, Data Ultima modifica
393
+ const desiredChronologyOrder = [
394
+ ChronologyMIDs.Ver,
395
+ SystemMIDsAsNumber.FileExt,
396
+ SystemMIDsAsNumber.FileSize,
397
+ ChronologyMIDs.AuthorID,
398
+ ChronologyMIDs.CheckInTime,
399
+ ];
400
+ const tempChronologyDataMap = {};
393
401
  metadataValues.forEach(item => {
394
402
  switch (item.md?.id) {
395
403
  case ChronologyMIDs.Ver:
396
404
  case ChronologyMIDs.AuthorID:
397
- chronologyData.push(item);
405
+ case ChronologyMIDs.CheckInTime:
406
+ case SystemMIDsAsNumber.FileExt:
407
+ case SystemMIDsAsNumber.FileSize:
408
+ tempChronologyDataMap[item.md.id] = item;
398
409
  break;
399
410
  default:
400
411
  break;
401
412
  }
402
413
  });
414
+ // Visualizziamo nell'ordine desiderato
415
+ const chronologyData = [];
416
+ desiredChronologyOrder.forEach(id => {
417
+ if (tempChronologyDataMap[id]) {
418
+ chronologyData.push(tempChronologyDataMap[id]);
419
+ }
420
+ });
403
421
  return (_jsx("div", { style: { width: '100%' }, children: chronologyData.length > 0 && chronologyData.map(item => renderMetadataItem(item, isReadOnly)) }));
404
422
  }, [metadataValues, showCheckBoxes, showNullValueCheckBoxes, isReadOnly, dynDataListsToBeRefreshed, validationItems, selectedMID, isOpenDistinctValues, openChooserBySingleClick, metadataValuesOrig]);
405
423
  const layoutDsAttachs = useMemo(() => {
@@ -550,7 +568,7 @@ const TMMetadataValues = ({ showCheckBoxes = ShowCheckBoxesMode.Never, checkPerm
550
568
  if (allSystem) {
551
569
  return metadataValues.map((item) => renderMetadataItem(item, true));
552
570
  }
553
- if (currentDTD?.templateTID === TemplateTIDs.WF_WIApprView && !isReadOnly) {
571
+ if (isApprovalWorkflowView(currentDTD) && !isReadOnly) {
554
572
  return layoutWorkItem;
555
573
  }
556
574
  switch (currentDTD?.id) {
@@ -9,7 +9,7 @@ import { TMExceptionBoxManager } from '../base/TMPopUp';
9
9
  import TMLayoutContainer, { TMLayoutItem } from '../base/TMLayout';
10
10
  import TMVilViewer from '../base/TMVilViewer';
11
11
  import TMTooltip from '../base/TMTooltip';
12
- import { ContextMenu } from 'devextreme-react';
12
+ import TMContextMenu from '../NewComponents/ContextMenu/TMContextMenu';
13
13
  import { DeviceType, useDeviceType } from '../base/TMDeviceProvider';
14
14
  import TMChooserForm from '../forms/TMChooserForm';
15
15
  import { FormulaItemHelper } from './TMTextExpression';
@@ -94,7 +94,10 @@ const TMTextBox = ({ autoFocus, maxLength, labelColor, precision, fromModal = fa
94
94
  if (formulaItems && formulaItems.length > 0) {
95
95
  let menuItems = [];
96
96
  for (const formula of formulaItems) {
97
- menuItems.push({ text: formula });
97
+ menuItems.push({
98
+ name: formula,
99
+ onClick: () => insertText(formula)
100
+ });
98
101
  }
99
102
  setFormulaMenuItems(menuItems);
100
103
  }
@@ -269,7 +272,7 @@ const TMTextBox = ({ autoFocus, maxLength, labelColor, precision, fromModal = fa
269
272
  onBlur?.(undefined);
270
273
  }, children: _jsx(IconClearButton, {}) }), buttons.map((buttonItem, index) => {
271
274
  return (_jsx(StyledTextBoxEditorButton, { onClick: buttonItem.onClick, children: _jsx(TMTooltip, { content: buttonItem.text, children: buttonItem.icon }) }, buttonItem.text));
272
- })] }), openFormulaItemsChooser(), formulaItems.length > 0 && (_jsx(ContextMenu, { dataSource: formulaMenuItems, target: `#text-${id}`, onItemClick: (e) => { insertText(e.itemData?.text ?? ''); } })), _jsx(TMVilViewer, { vil: validationItems })] }));
275
+ })] }), openFormulaItemsChooser(), formulaItems.length > 0 && (_jsx(TMContextMenu, { items: formulaMenuItems, target: `#text-${id}` })), _jsx(TMVilViewer, { vil: validationItems })] }));
273
276
  };
274
277
  const renderedLeftLabelTextBox = () => {
275
278
  return (_jsxs(TMLayoutContainer, { direction: 'horizontal', children: [icon && _jsx(TMLayoutItem, { width: '20px', children: _jsx(StyledEditorIcon, { "$disabled": disabled, "$vil": validationItems, "$isModified": isModifiedWhen, children: icon }) }), _jsx(TMLayoutItem, { children: _jsxs(StyledEditorContainer, { "$width": width, children: [label && _jsx(StyledEditorLabel, { "$color": labelColor, "$isFocused": isFocused, "$labelPosition": labelPosition, "$disabled": disabled, children: label }), renderInputField()] }) })] }));
@@ -1,6 +1,18 @@
1
1
  import React from 'react';
2
2
  import { HomeBlogPost, LayoutModes, ObjectRef, SearchResultDescriptor, TaskDescriptor, ValidationItem } from '@topconsultnpm/sdk-ts';
3
3
  import { DcmtInfo, FormModes, MetadataValueDescriptorEx, TaskContext } from '../../../ts';
4
+ /**
5
+ * Definisce il contesto da cui è stato invocato il TMDcmtForm.
6
+ * Permette di gestire logiche diverse in base alla provenienza.
7
+ */
8
+ export declare enum InvocationContext {
9
+ /** Invocazione standard */
10
+ Default = "default",
11
+ /** Invocato dalla pagina Todo/Task */
12
+ Todo = "todo",
13
+ /** Invocato dalla pagina WorkflowCtrl */
14
+ WorkflowCtrl = "workflowCtrl"
15
+ }
4
16
  interface ITMDcmtFormProps {
5
17
  allTasks?: Array<TaskDescriptor>;
6
18
  getAllTasks?: () => Promise<void>;
@@ -24,7 +36,7 @@ interface ITMDcmtFormProps {
24
36
  canPrev?: boolean;
25
37
  isClosable?: boolean;
26
38
  groupId?: string;
27
- invokedByTodo?: boolean;
39
+ invocationContext?: InvocationContext;
28
40
  taskFormDialogComponent?: React.ReactNode;
29
41
  taskMoreInfo?: TaskDescriptor;
30
42
  showBackButton?: boolean;