@topconsultnpm/sdkui-react 6.22.0-dev2.5 → 6.22.0-dev2.50

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 (137) hide show
  1. package/lib/components/NewComponents/ContextMenu/TMContextMenu.js +1 -1
  2. package/lib/components/NewComponents/FloatingMenuBar/TMFloatingMenuBar.js +1 -1
  3. package/lib/components/base/TMDataGrid.d.ts +2 -0
  4. package/lib/components/base/TMDataGrid.js +260 -8
  5. package/lib/components/base/TMEditorBase.d.ts +2 -0
  6. package/lib/components/base/TMFileManager.js +5 -3
  7. package/lib/components/base/TMFileManagerDataGridView.js +11 -2
  8. package/lib/components/base/TMFileManagerThumbnailItems.js +19 -9
  9. package/lib/components/base/TMFileManagerUtils.d.ts +2 -0
  10. package/lib/components/base/TMFileManagerUtils.js +37 -1
  11. package/lib/components/base/TMModal.d.ts +11 -0
  12. package/lib/components/base/TMModal.js +47 -13
  13. package/lib/components/base/TMPanel.d.ts +6 -0
  14. package/lib/components/base/TMPanel.js +221 -108
  15. package/lib/components/base/TMPopUp.js +3 -0
  16. package/lib/components/base/TMTooltip.d.ts +2 -1
  17. package/lib/components/base/TMTooltip.js +24 -8
  18. package/lib/components/base/TMTreeView.js +108 -67
  19. package/lib/components/choosers/TMDcmtTypeChooser.js +4 -3
  20. package/lib/components/choosers/TMDistinctValues.d.ts +9 -7
  21. package/lib/components/choosers/TMDistinctValues.js +149 -142
  22. package/lib/components/choosers/TMMetadataChooser.js +1 -1
  23. package/lib/components/choosers/TMQuickSearchInfo.d.ts +12 -0
  24. package/lib/components/choosers/TMQuickSearchInfo.js +279 -0
  25. package/lib/components/choosers/TMQuickSearchSettingsForm.d.ts +16 -0
  26. package/lib/components/choosers/TMQuickSearchSettingsForm.js +94 -0
  27. package/lib/components/choosers/TMSelectedValuesSummary.d.ts +13 -0
  28. package/lib/components/choosers/TMSelectedValuesSummary.js +91 -0
  29. package/lib/components/editors/TMDropDown.d.ts +3 -0
  30. package/lib/components/editors/TMDropDown.js +197 -5
  31. package/lib/components/editors/TMMetadataEditor.d.ts +5 -1
  32. package/lib/components/editors/TMMetadataEditor.js +8 -3
  33. package/lib/components/editors/TMTextBox.js +2 -2
  34. package/lib/components/features/archive/TMArchive.js +17 -3
  35. package/lib/components/features/documents/TMBatchUpdateForm.js +19 -5
  36. package/lib/components/features/documents/TMDcmtBlog.d.ts +3 -0
  37. package/lib/components/features/documents/TMDcmtBlog.js +4 -4
  38. package/lib/components/features/documents/TMDcmtForm.d.ts +7 -0
  39. package/lib/components/features/documents/TMDcmtForm.js +151 -46
  40. package/lib/components/features/documents/TMDcmtFormActionButtons.d.ts +11 -0
  41. package/lib/components/features/documents/TMDcmtFormActionButtons.js +74 -7
  42. package/lib/components/features/documents/TMDcmtIcon.js +5 -3
  43. package/lib/components/features/documents/TMDcmtPreview.js +10 -6
  44. package/lib/components/features/documents/TMMasterDetailDcmts.js +95 -33
  45. package/lib/components/features/documents/TMMasterInfoFields.d.ts +19 -0
  46. package/lib/components/features/documents/TMMasterInfoFields.js +186 -0
  47. package/lib/components/features/documents/TMMergeToPdfForm.d.ts +1 -2
  48. package/lib/components/features/documents/TMMergeToPdfForm.js +30 -5
  49. package/lib/components/features/documents/TMMultiMasterDetailDcmtsForm.d.ts +45 -0
  50. package/lib/components/features/documents/TMMultiMasterDetailDcmtsForm.js +323 -0
  51. package/lib/components/features/documents/TMMultiMasterDetailDcmtsUtils.d.ts +370 -0
  52. package/lib/components/features/documents/TMMultiMasterDetailDcmtsUtils.js +283 -0
  53. package/lib/components/features/documents/TMRelationViewer.d.ts +14 -1
  54. package/lib/components/features/documents/TMRelationViewer.js +69 -20
  55. package/lib/components/features/search/TMSearch.js +77 -11
  56. package/lib/components/features/search/TMSearchQueryEditor.js +5 -3
  57. package/lib/components/features/search/TMSearchQueryPanel.d.ts +4 -0
  58. package/lib/components/features/search/TMSearchQueryPanel.js +141 -67
  59. package/lib/components/features/search/TMSearchResult.d.ts +16 -0
  60. package/lib/components/features/search/TMSearchResult.js +432 -109
  61. package/lib/components/features/search/TMTreeSelector.js +166 -130
  62. package/lib/components/features/workflow/TMWorkflowPopup.d.ts +10 -0
  63. package/lib/components/features/workflow/TMWorkflowPopup.js +8 -4
  64. package/lib/components/grids/TMBlogAttachments.js +13 -2
  65. package/lib/components/grids/TMBlogsPost.d.ts +2 -0
  66. package/lib/components/grids/TMBlogsPost.js +26 -3
  67. package/lib/components/grids/TMBlogsPostUtils.d.ts +1 -0
  68. package/lib/components/grids/TMBlogsPostUtils.js +14 -3
  69. package/lib/components/layout/panelManager/TMPanelManagerContainer.d.ts +1 -0
  70. package/lib/components/layout/panelManager/TMPanelManagerContainer.js +24 -14
  71. package/lib/components/layout/panelManager/TMPanelManagerContext.js +68 -93
  72. package/lib/components/layout/panelManager/TMPanelWrapper.js +2 -2
  73. package/lib/components/layout/panelManager/types.d.ts +3 -0
  74. package/lib/components/layout/panelManager/utils.js +13 -11
  75. package/lib/components/sidebar/TMHeader.js +30 -20
  76. package/lib/components/viewers/TMMidViewer.js +4 -1
  77. package/lib/components/viewers/TMTidViewer.js +83 -22
  78. package/lib/devextreme-license.d.ts +1 -0
  79. package/lib/devextreme-license.js +3 -0
  80. package/lib/helper/SDKUI_Globals.d.ts +110 -0
  81. package/lib/helper/SDKUI_Globals.js +151 -0
  82. package/lib/helper/SDKUI_Localizator.d.ts +42 -0
  83. package/lib/helper/SDKUI_Localizator.js +420 -0
  84. package/lib/helper/TMAppUpdatedModal.d.ts +1 -0
  85. package/lib/helper/TMAppUpdatedModal.js +134 -0
  86. package/lib/helper/TMIcons.d.ts +1 -0
  87. package/lib/helper/TMIcons.js +3 -0
  88. package/lib/helper/TMUtils.d.ts +7 -0
  89. package/lib/helper/TMUtils.js +15 -1
  90. package/lib/helper/dataGridSearchHelper.d.ts +28 -0
  91. package/lib/helper/dataGridSearchHelper.js +51 -0
  92. package/lib/helper/dcmtsHelper.d.ts +20 -0
  93. package/lib/helper/dcmtsHelper.js +58 -1
  94. package/lib/helper/helpers.d.ts +11 -0
  95. package/lib/helper/helpers.js +25 -1
  96. package/lib/helper/index.d.ts +2 -0
  97. package/lib/helper/index.js +2 -0
  98. package/lib/helper/queryHelper.d.ts +6 -1
  99. package/lib/helper/queryHelper.js +8 -3
  100. package/lib/hooks/tmDistinctValuesGridHelper.d.ts +16 -0
  101. package/lib/hooks/tmDistinctValuesGridHelper.js +31 -0
  102. package/lib/hooks/useArchiveListForm.d.ts +39 -0
  103. package/lib/hooks/useArchiveListForm.js +46 -0
  104. package/lib/hooks/useCaseFlowApprove.d.ts +56 -0
  105. package/lib/hooks/useCaseFlowApprove.js +157 -0
  106. package/lib/hooks/useDataUserIdItem.d.ts +1 -0
  107. package/lib/hooks/useDataUserIdItem.js +1 -0
  108. package/lib/hooks/useDocumentOperations.d.ts +4 -0
  109. package/lib/hooks/useDocumentOperations.js +50 -10
  110. package/lib/hooks/useMultiMasterDetailDcmts.d.ts +113 -0
  111. package/lib/hooks/useMultiMasterDetailDcmts.js +760 -0
  112. package/lib/hooks/useRelatedDocuments.d.ts +1 -0
  113. package/lib/hooks/useRelatedDocuments.js +22 -27
  114. package/lib/hooks/useShowDossiersV5.d.ts +12 -0
  115. package/lib/hooks/useShowDossiersV5.js +37 -0
  116. package/lib/hooks/useTMDistinctValuesMetadataDisplay.d.ts +18 -0
  117. package/lib/hooks/useTMDistinctValuesMetadataDisplay.js +103 -0
  118. package/lib/hooks/useTMDistinctValuesQuickSearch.d.ts +49 -0
  119. package/lib/hooks/useTMDistinctValuesQuickSearch.js +307 -0
  120. package/lib/hooks/useTMDistinctValuesSelection.d.ts +42 -0
  121. package/lib/hooks/useTMDistinctValuesSelection.js +103 -0
  122. package/lib/hooks/useTMDistinctValuesSource.d.ts +29 -0
  123. package/lib/hooks/useTMDistinctValuesSource.js +105 -0
  124. package/lib/index.d.ts +2 -0
  125. package/lib/index.js +5 -2
  126. package/lib/services/caseflow/CaseFlowService.d.ts +236 -0
  127. package/lib/services/caseflow/CaseFlowService.js +693 -0
  128. package/lib/services/caseflow/CaseFlowTemplateCacheService.d.ts +28 -0
  129. package/lib/services/caseflow/CaseFlowTemplateCacheService.js +121 -0
  130. package/lib/services/caseflow/caseFlowNameCache.d.ts +32 -0
  131. package/lib/services/caseflow/caseFlowNameCache.js +116 -0
  132. package/lib/services/caseflow/caseFlowWorkItemUtils.d.ts +61 -0
  133. package/lib/services/caseflow/caseFlowWorkItemUtils.js +113 -0
  134. package/lib/services/index.d.ts +4 -0
  135. package/lib/services/index.js +4 -0
  136. package/lib/services/platform_services.d.ts +1 -1
  137. package/package.json +9 -5
@@ -500,6 +500,6 @@ const TMContextMenu = ({ items, trigger = 'right', children, target, externalCon
500
500
  // display: 'inline-block',
501
501
  WebkitTouchCallout: isIOS ? 'none' : undefined,
502
502
  WebkitUserSelect: isIOS ? 'none' : undefined,
503
- }, children: children })), menuState.visible && createPortal(_jsxs(_Fragment, { children: [_jsxs(S.MenuContainer, { ref: menuRef, "$x": menuState.position.x, "$y": menuState.position.y, "$openLeft": openLeft, "$openUp": openUp, "$isPositioned": isCalculated, "$externalControl": !!externalControl, "$needsScroll": needsScroll, "$maxHeight": maxHeight, children: [isMobile && menuState.parentNames.length > 0 && (_jsxs(S.MobileMenuHeader, { children: [_jsx(S.BackButton, { onClick: handleBack, "aria-label": "Go back", children: _jsx(IconArrowLeft, {}) }), _jsx(S.HeaderTitle, { children: currentParentName })] })), renderMenuItems(currentMenu, 0)] }), !isMobile && hoveredSubmenus.map((submenu, idx) => (_jsx(S.Submenu, { "$parentRect": submenu.parentRect, "$openUp": submenu.openUp, "data-submenu": "true", "data-open-up": submenu.openUp ? 'true' : 'false', onMouseEnter: handleSubmenuMouseEnter, onMouseLeave: () => handleMouseLeave(submenu.depth), children: renderMenuItems(submenu.items, submenu.depth) }, `submenu-${submenu.depth}-${idx}`)))] }), document.body)] }));
503
+ }, children: children })), menuState.visible && createPortal(_jsxs(_Fragment, { children: [_jsxs(S.MenuContainer, { ref: menuRef, className: "notranslate", translate: "no", "$x": menuState.position.x, "$y": menuState.position.y, "$openLeft": openLeft, "$openUp": openUp, "$isPositioned": isCalculated, "$externalControl": !!externalControl, "$needsScroll": needsScroll, "$maxHeight": maxHeight, children: [isMobile && menuState.parentNames.length > 0 && (_jsxs(S.MobileMenuHeader, { children: [_jsx(S.BackButton, { onClick: handleBack, "aria-label": "Go back", children: _jsx(IconArrowLeft, {}) }), _jsx(S.HeaderTitle, { children: currentParentName })] })), renderMenuItems(currentMenu, 0)] }), !isMobile && hoveredSubmenus.map((submenu, idx) => (_jsx(S.Submenu, { className: "notranslate", translate: "no", "$parentRect": submenu.parentRect, "$openUp": submenu.openUp, "data-submenu": "true", "data-open-up": submenu.openUp ? 'true' : 'false', onMouseEnter: handleSubmenuMouseEnter, onMouseLeave: () => handleMouseLeave(submenu.depth), children: renderMenuItems(submenu.items, submenu.depth) }, `submenu-${submenu.depth}-${idx}`)))] }), document.body)] }));
504
504
  };
505
505
  export default TMContextMenu;
@@ -837,7 +837,7 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], isConstrained
837
837
  setState(s => ({ ...s, draggedItemIndex: null }));
838
838
  setDragOverIndex(null);
839
839
  };
840
- return (_jsxs(S.FloatingContainer, { ref: floatingRef, "$x": pixelPosition.x, "$y": pixelPosition.y, "$orientation": state.orientation, "$verticalDirection": state.verticalDirection, "$isDragging": state.isDragging, "$isConfigMode": false, "$isConstrained": isConstrained, "$isHidden": isOrientationChanging, "$bgColor": bgColor, onContextMenu: undefined, children: [_jsx(ContextMenu, { items: [
840
+ return (_jsxs(S.FloatingContainer, { ref: floatingRef, className: "notranslate", translate: "no", "$x": pixelPosition.x, "$y": pixelPosition.y, "$orientation": state.orientation, "$verticalDirection": state.verticalDirection, "$isDragging": state.isDragging, "$isConfigMode": false, "$isConstrained": isConstrained, "$isHidden": isOrientationChanging, "$bgColor": bgColor, onContextMenu: undefined, children: [_jsx(ContextMenu, { items: [
841
841
  {
842
842
  name: state.orientation === 'horizontal' ? 'Floating bar verticale' : 'Floating bar orizzontale',
843
843
  icon: _jsx(IconRotate, { fontSize: 16, style: { transform: state.orientation === 'horizontal' ? 'rotate(90deg)' : 'rotate(0deg)' } }),
@@ -46,6 +46,8 @@ export interface TMDataGridProps<T> extends IDataGridOptions {
46
46
  showSearchPanel?: boolean;
47
47
  /** Show the group panel */
48
48
  showGroupPanel?: boolean;
49
+ /** Rende il paginatore compatto (meno alto, font e pulsanti ridotti, page numbers sostituiti da "pagina / totale"): utile quando la griglia è dentro pannelli bassi */
50
+ compactPager?: boolean;
49
51
  /** Counter configuration */
50
52
  counterConfig?: ITMCounterContainerProps;
51
53
  /** Master Detail */
@@ -1,5 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import React, { useCallback, useEffect, useImperativeHandle, useRef, useState } from 'react';
2
+ import React, { useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react';
3
+ import styled, { createGlobalStyle, css } from 'styled-components';
3
4
  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
5
  import DataSource from 'devextreme/data/data_source';
5
6
  import { IconAll, IconSelected, IconVisible, SDKUI_Globals, SDKUI_Localizator } from '../../helper';
@@ -18,7 +19,7 @@ const TMDataGrid = React.forwardRef((props, ref) => {
18
19
  // main properties
19
20
  keyExpr = 'id', dataSource, focusedRowEnabled = true, hoverStateEnabled = true, focusedRowKey, selectedRowKeys = [],
20
21
  // custom options
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,
22
+ dataColumns = [], pageSize = TMDataGridPageSize.Large, showHeaderFilter = true, showFilterPanel = true, showHeaderColumnChooser = false, showLoadPanel = true, showSearchPanel = true, searchPanelToolbarPosition = 'before', searchPanelFocusTrigger = 0, counterConfig = { show: false, items: new Map() }, compactPager = false, onHasFiltersChange, customContextMenuItems,
22
23
  // events and callbacks
23
24
  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
25
  // other properties
@@ -35,6 +36,9 @@ const TMDataGrid = React.forwardRef((props, ref) => {
35
36
  const [customContextMenuVisible, setCustomContextMenuVisible] = useState(false);
36
37
  const [customContextMenuPosition, setCustomContextMenuPosition] = useState({ x: 0, y: 0 });
37
38
  const [customContextMenuRowKey, setCustomContextMenuRowKey] = useState(undefined);
39
+ // true quando il menu contestuale viene aperto su spazio vuoto senza alcuna riga di riferimento:
40
+ // in tal caso i comandi legati alla riga (singleRow/multiRow) devono risultare disabilitati
41
+ const [customContextMenuOnEmptyArea, setCustomContextMenuOnEmptyArea] = useState(false);
38
42
  const gridContainerRef = useRef(null);
39
43
  // Ref per evitare focus ripetuti sulla search panel
40
44
  const searchPanelFocusedRef = useRef(false);
@@ -75,9 +79,17 @@ const TMDataGrid = React.forwardRef((props, ref) => {
75
79
  const rowKey = internalRef.current.instance().getKeyByRowIndex(rowIndex);
76
80
  internalRef.current.instance().option('focusedRowKey', rowKey);
77
81
  setCustomContextMenuRowKey(rowKey);
82
+ setCustomContextMenuOnEmptyArea(false);
78
83
  }
79
84
  else {
80
- setCustomContextMenuRowKey(focusedRowKey);
85
+ // Right-click su spazio vuoto: ricade sulla riga focalizzata solo se esiste ancora.
86
+ // Se non c'è una riga focalizzata (es. primo click dopo l'apertura) o se focusedRowKey punta a
87
+ // una riga non più presente (dopo un'eliminazione), il menu viene comunque mostrato ma senza
88
+ // riga di riferimento: i comandi di riga restano disabilitati, quelli generali utilizzabili
89
+ const grid = internalRef.current?.instance();
90
+ const focusedRowExists = focusedRowKey !== undefined && !!grid && grid.getRowIndexByKey(focusedRowKey) >= 0;
91
+ setCustomContextMenuRowKey(focusedRowExists ? focusedRowKey : undefined);
92
+ setCustomContextMenuOnEmptyArea(!focusedRowExists);
81
93
  }
82
94
  setCustomContextMenuVisible(true);
83
95
  setCustomContextMenuPosition({ x: e.clientX, y: e.clientY });
@@ -114,6 +126,7 @@ const TMDataGrid = React.forwardRef((props, ref) => {
114
126
  setCustomContextMenuVisible(true);
115
127
  setCustomContextMenuPosition({ x: clientX, y: clientY });
116
128
  setCustomContextMenuRowKey(rowKey);
129
+ setCustomContextMenuOnEmptyArea(false);
117
130
  },
118
131
  });
119
132
  // Creating a ref to store the timestamp of the last selection change
@@ -222,7 +235,8 @@ const TMDataGrid = React.forwardRef((props, ref) => {
222
235
  return items.map(item => {
223
236
  let disabled = item.disabled ?? false;
224
237
  let disabledCalculation = false;
225
- const id = focusedRowEnabled ? focusedRowKey : rowID;
238
+ // Menu aperto su spazio vuoto senza riga di riferimento: nessun id, i comandi di riga sono disabilitati
239
+ const id = customContextMenuOnEmptyArea ? undefined : (focusedRowEnabled ? focusedRowKey : rowID);
226
240
  if (item.operationType === 'singleRow') {
227
241
  disabledCalculation = selectedRowKeys.length > 1 || id === undefined;
228
242
  }
@@ -237,7 +251,10 @@ const TMDataGrid = React.forwardRef((props, ref) => {
237
251
  if (item.operationType === 'singleRow' && id !== undefined) {
238
252
  originalOnClick(id);
239
253
  }
240
- else if (item.operationType === 'multiRow' && id !== undefined) {
254
+ else if (item.operationType === 'multiRow' && (selectedRowKeys.length > 0 || id !== undefined)) {
255
+ // Condizione allineata a quella di disabilitazione: con righe selezionate il comando è
256
+ // attivo anche senza riga di riferimento (es. menu aperto su spazio vuoto), quindi qui
257
+ // devono comunque essere passate le chiavi selezionate e non un onClick senza argomenti
241
258
  if (selectedRowKeys.length > 0) {
242
259
  originalOnClick(selectedRowKeys);
243
260
  }
@@ -252,7 +269,7 @@ const TMDataGrid = React.forwardRef((props, ref) => {
252
269
  submenu: item.submenu ? processCustomContextMenuItems(item.submenu, id) : undefined,
253
270
  };
254
271
  });
255
- }, [focusedRowEnabled, focusedRowKey, selectedRowKeys]);
272
+ }, [focusedRowEnabled, focusedRowKey, selectedRowKeys, customContextMenuOnEmptyArea]);
256
273
  // Gestisce la preparazione del menu contestuale della griglia (header e righe)
257
274
  const onContextMenuPreparingCallback = useCallback((e) => {
258
275
  if (e === undefined)
@@ -358,7 +375,14 @@ const TMDataGrid = React.forwardRef((props, ref) => {
358
375
  // Propaga l'evento originale
359
376
  onOptionChanged?.(e);
360
377
  }, [onOptionChanged, onHasFiltersChange]);
361
- 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' : ''}`,
378
+ // In modalità compatta il pager usa il displayMode 'compact' di DevExtreme (page numbers sostituiti da "pagina / totale"),
379
+ // salvo displayMode esplicito passato dal chiamante
380
+ const effectivePager = useMemo(() => {
381
+ if (!pager || !compactPager)
382
+ return pager;
383
+ return { ...pager, displayMode: pager.displayMode ?? 'compact' };
384
+ }, [pager, compactPager]);
385
+ return _jsxs(StyledDataGridContainer, { "$compactPager": compactPager, style: { width: "100%", height: "100%" }, children: [_jsx(HeaderFilterMenuGlobalStyle, {}), _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' : ''}`,
362
386
  // main properties
363
387
  keyExpr: keyExpr, dataSource: dataSource, selectedRowKeys: selectedRowKeys, focusedRowEnabled: focusedRowEnabled, hoverStateEnabled: hoverStateEnabled,
364
388
  // events and callbacks
@@ -371,13 +395,241 @@ const TMDataGrid = React.forwardRef((props, ref) => {
371
395
  // Temporary: iOS-specific styles to prevent default long-press menu and text selection
372
396
  WebkitTouchCallout: 'none',
373
397
  WebkitUserSelect: 'none'
374
- }, 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: {
398
+ }, children: [dataColumns.map((column, index) => (_jsx(Column, { ...column, alignment: column.alignment ?? 'left' }, 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, search: { enabled: true, ...headerFilter?.search } }), 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 }), effectivePager && _jsx(Pager, { ...effectivePager, 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: {
375
399
  visible: customContextMenuVisible,
376
400
  position: customContextMenuPosition,
377
401
  onClose: () => setCustomContextMenuVisible(false)
378
402
  } }))] });
379
403
  });
380
404
  export default TMDataGrid;
405
+ // Contenitore della griglia: in modalità compatta riduce l'ingombro verticale del pager DevExtreme
406
+ // (padding, altezza minima, font e dimensione dei pulsanti di pagina).
407
+ // Con compactPager = false non emette nessuna regola: width/height restano inline come in precedenza,
408
+ // così il rendering è identico a quello del div originale.
409
+ const StyledDataGridContainer = styled.div `
410
+ ${({ $compactPager }) => $compactPager && css `
411
+ & .dx-datagrid-pager {
412
+ padding: 2px 4px !important;
413
+ min-height: 0 !important;
414
+ font-size: 11px;
415
+ }
416
+
417
+ & .dx-datagrid-pager .dx-page,
418
+ & .dx-datagrid-pager .dx-page-size,
419
+ & .dx-datagrid-pager .dx-selection,
420
+ & .dx-datagrid-pager .dx-navigate-button {
421
+ min-width: 18px !important;
422
+ min-height: 18px !important;
423
+ height: auto !important;
424
+ padding: 1px 5px !important;
425
+ line-height: 16px !important;
426
+ font-size: 11px;
427
+ }
428
+
429
+ & .dx-datagrid-pager .dx-pages,
430
+ & .dx-datagrid-pager .dx-page-sizes,
431
+ & .dx-datagrid-pager .dx-info,
432
+ & .dx-datagrid-pager .dx-page-index,
433
+ & .dx-datagrid-pager .dx-pages .dx-info {
434
+ font-size: 11px;
435
+ margin-top: 0 !important;
436
+ margin-bottom: 0 !important;
437
+ }
438
+
439
+ & .dx-datagrid-pager .dx-info {
440
+ margin-left: 4px !important;
441
+ margin-right: 4px !important;
442
+ }
443
+
444
+ /* Editor del numero di pagina (displayMode compact) */
445
+ & .dx-datagrid-pager .dx-page-index .dx-texteditor-input,
446
+ & .dx-datagrid-pager .dx-page-sizes .dx-texteditor-input {
447
+ min-height: 18px !important;
448
+ height: 18px !important;
449
+ padding: 0 4px !important;
450
+ font-size: 11px;
451
+ }
452
+ `}
453
+ `;
454
+ // Stile del pannello del filtro d'intestazione (ricerca, elenco valori, OK/Annulla).
455
+ // Il popup è in portale sul body, fuori da StyledDataGridContainer: le regole sono globali
456
+ // ma tutte sotto .dx-header-filter-menu, classe che DevExtreme applica solo a questo popup.
457
+ const HeaderFilterMenuGlobalStyle = createGlobalStyle `
458
+ .dx-header-filter-menu {
459
+
460
+ &.dx-popup-wrapper > .dx-overlay-content.dx-popup-normal {
461
+ border: 1px solid #E4E8EE;
462
+ border-radius: 8px;
463
+ box-shadow: 0 2px 6px rgba(18, 44, 76, .08), 0 12px 28px rgba(18, 44, 76, .14);
464
+ overflow: hidden;
465
+ }
466
+
467
+ &.dx-popup-wrapper .dx-popup-content {
468
+ padding: 10px 10px 4px;
469
+ }
470
+
471
+ /* Campo di ricerca: TextBox mode "search" resa da List o da TreeView (filtri gerarchici) */
472
+ .dx-searchbox.dx-list-search,
473
+ .dx-searchbox.dx-treeview-search {
474
+ margin-bottom: 8px;
475
+ border-radius: 6px;
476
+ border: 1px solid #CDD2D8;
477
+ background-color: #F4F6F9;
478
+ box-shadow: none;
479
+ transition: border-color .15s ease, background-color .15s ease, box-shadow .15s ease;
480
+
481
+ /* fluent disegna qui la barretta di focus, sostituita da bordo + alone */
482
+ &::before,
483
+ &::after {
484
+ display: none;
485
+ }
486
+
487
+ &.dx-state-hover:not(.dx-state-focused) {
488
+ border-color: #AEB6C1;
489
+ background-color: #EEF2F7;
490
+ }
491
+
492
+ &.dx-state-focused {
493
+ border-color: #2559A5;
494
+ background-color: #FFFFFF;
495
+ box-shadow: 0 0 0 2px rgba(37, 89, 165, .16);
496
+ }
497
+
498
+ .dx-icon-search {
499
+ width: 28px;
500
+ color: #8A929B;
501
+ transition: color .15s ease;
502
+ }
503
+
504
+ &.dx-state-focused .dx-icon-search {
505
+ color: #2559A5;
506
+ }
507
+
508
+ .dx-texteditor-input {
509
+ min-height: 28px;
510
+ padding-inline-start: 28px;
511
+ padding-inline-end: 8px;
512
+ font-size: 12px;
513
+ background-color: transparent;
514
+ }
515
+
516
+ .dx-placeholder {
517
+ color: #9AA3AD;
518
+ font-size: 12px;
519
+
520
+ &::before {
521
+ padding-inline-start: 28px;
522
+ padding-inline-end: 8px;
523
+ }
524
+ }
525
+
526
+ .dx-clear-button-area .dx-icon-clear {
527
+ color: #8A929B;
528
+ transition: color .15s ease;
529
+ }
530
+
531
+ .dx-clear-button-area:hover .dx-icon-clear {
532
+ color: #2559A5;
533
+ }
534
+ }
535
+
536
+ .dx-list-item {
537
+ border-radius: 4px;
538
+ transition: background-color .12s ease;
539
+ }
540
+
541
+ .dx-list-item-content {
542
+ padding: 4px 6px;
543
+ }
544
+
545
+ .dx-list-item.dx-state-hover,
546
+ .dx-list-item.dx-state-focused {
547
+ background-color: #F1F6FD;
548
+ color: #122C4C;
549
+ }
550
+
551
+ .dx-list-select-all {
552
+ padding: 2px 0 6px;
553
+ margin-bottom: 4px;
554
+ border-bottom: 1px solid #ECEFF3;
555
+ }
556
+
557
+ .dx-list-select-all-label {
558
+ font-weight: 600;
559
+ color: #122C4C;
560
+ }
561
+
562
+ .dx-checkbox-checked .dx-checkbox-icon,
563
+ .dx-checkbox-indeterminate .dx-checkbox-icon {
564
+ border-color: #2559A5;
565
+ background-color: #2559A5;
566
+ }
567
+
568
+ .dx-checkbox.dx-state-hover:not(.dx-checkbox-checked) .dx-checkbox-icon {
569
+ border-color: #2559A5;
570
+ }
571
+
572
+ /* il :not() lascia intatto il fade-out nativo della scrollbar */
573
+ .dx-scrollable-scroll:not(.dx-state-invisible) .dx-scrollable-scroll-content {
574
+ background-color: rgba(18, 44, 76, .28);
575
+ border-radius: 3px;
576
+ }
577
+
578
+ &.dx-popup-wrapper .dx-popup-bottom.dx-toolbar {
579
+ padding: 8px 10px 10px;
580
+ border-top: 1px solid #ECEFF3;
581
+ }
582
+
583
+ .dx-popup-bottom .dx-button {
584
+ border-radius: 5px;
585
+ min-width: 76px;
586
+ margin: 0;
587
+ }
588
+
589
+ .dx-popup-bottom .dx-toolbar-button + .dx-toolbar-button {
590
+ margin-inline-start: 6px;
591
+
592
+ .dx-button {
593
+ margin: 0;
594
+ }
595
+ }
596
+
597
+ /* DevExtreme aggiunge prima OK e poi Annulla: individuarli per posizione li rende indipendenti dalla lingua */
598
+ .dx-popup-bottom .dx-toolbar-after > .dx-toolbar-button:first-child .dx-button {
599
+ border-color: transparent;
600
+ background-color: #2559A5;
601
+
602
+ .dx-button-text {
603
+ color: #FFFFFF;
604
+ }
605
+
606
+ &.dx-state-hover {
607
+ background-color: #1E4A8C;
608
+ }
609
+
610
+ &.dx-state-active {
611
+ background-color: #1A3F78;
612
+ }
613
+ }
614
+
615
+ .dx-popup-bottom .dx-toolbar-after > .dx-toolbar-button + .dx-toolbar-button .dx-button {
616
+ border-color: transparent;
617
+ background-color: transparent;
618
+
619
+ .dx-button-text {
620
+ color: #44506B;
621
+ }
622
+
623
+ &.dx-state-hover {
624
+ background-color: #F0F3F7;
625
+ }
626
+
627
+ &.dx-state-active {
628
+ background-color: #E6EBF2;
629
+ }
630
+ }
631
+ }
632
+ `;
381
633
  const getRecordCount = (dataSource) => {
382
634
  if (Array.isArray(dataSource)) {
383
635
  return dataSource.length; // For array
@@ -1,3 +1,4 @@
1
+ import React from "react";
1
2
  import { ValidationItem } from "@topconsultnpm/sdk-ts";
2
3
  export type Colors = 'error' | 'warning' | 'success' | 'info' | 'primary' | 'secondary' | 'tertiary' | 'standard';
3
4
  type IconModes = 'outside' | 'inside' | 'none';
@@ -6,6 +7,7 @@ export type Sizes = 'small' | 'medium' | 'large';
6
7
  export type TMEditorButtonData = {
7
8
  icon: any;
8
9
  text?: string;
10
+ tooltipContent?: React.ReactNode;
9
11
  onClick?: () => void;
10
12
  };
11
13
  export interface ITMEditorBase {
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useCallback, useEffect, useMemo, useState } from "react";
3
- import { extractTextsFromDirectory, findFileItems, setFolderTreeViewItems } from "./TMFileManagerUtils";
3
+ import { extractTextsFromDirectory, findFileItems, resolveFileItemUserNames, setFolderTreeViewItems } from "./TMFileManagerUtils";
4
4
  import { DeviceType, useDeviceType } from "./TMDeviceProvider";
5
5
  import { formatBytes, Globalization, IconDashboard, IconFolder, IconHide, IconList, IconMenuVertical, IconRefresh, IconShow, SDKUI_Globals, SDKUI_Localizator, TMCommandsContextMenu, TMConditionalWrapper } from "../../helper";
6
6
  import TMContextMenu from '../NewComponents/ContextMenu/TMContextMenu';
@@ -91,10 +91,12 @@ const TMFileManager = (props) => {
91
91
  (Globalization.getDateTimeDisplayValue(item.lastUpdateTime)?.toLowerCase().toString().includes(searchText.toLowerCase().trim())) ||
92
92
  (Globalization.getDateTimeDisplayValue(item.creationTime)?.toLowerCase().toString().includes(searchText.toLowerCase().trim())) ||
93
93
  (item.version?.toString().includes(searchText.toLowerCase().trim()))));
94
- setFilteredFileItems(filtered);
94
+ // I nomi utente possono mancare quando la lista viene ricostruita senza i partecipanti
95
+ // (es. refresh dopo la condivisione di un file): vengono risolti qui dagli ID
96
+ setFilteredFileItems(filtered.map(item => resolveFileItemUserNames(item, allUsers)));
95
97
  };
96
98
  filterItems();
97
- }, [searchText, selectedFolder]);
99
+ }, [searchText, selectedFolder, allUsers]);
98
100
  // Callback to handle the "back" action (closing the draft list view)
99
101
  const onBackCallback = useCallback(() => {
100
102
  setOpenDraftList(false);
@@ -1,5 +1,6 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useCallback, useEffect, useMemo, useState } from "react";
3
+ import { getFileItemLinkUrl } from "./TMFileManagerUtils";
3
4
  import { formatBytes, Globalization, renderHighlightedText, SDKUI_Localizator } from "../../helper";
4
5
  import TMDataGrid from "./TMDataGrid";
5
6
  import TMDcmtIcon from "../features/documents/TMDcmtIcon";
@@ -43,6 +44,12 @@ const TMFileManagerDataGridView = (props) => {
43
44
  }, [handleSelectedFiles]);
44
45
  // Handler for double-click cell event
45
46
  const onCellDblClick = useCallback((e) => {
47
+ // i link non hanno un documento da aprire: il doppio click (anche sull'icona dell'estensione) apre l'url in un nuovo tab
48
+ const linkUrl = getFileItemLinkUrl(e.data);
49
+ if (linkUrl) {
50
+ window.open(linkUrl, '_blank', 'noopener,noreferrer');
51
+ return;
52
+ }
46
53
  if (e.column.dataField === "ext")
47
54
  return;
48
55
  if (onDoubleClickHandler)
@@ -62,8 +69,10 @@ const TMFileManagerDataGridView = (props) => {
62
69
  }, [searchText, findCheckOutUserName]);
63
70
  const cellExtRender = useCallback((cellData) => {
64
71
  const item = cellData.data;
65
- const tooltipContent = (_jsxs("div", { style: { textAlign: 'left' }, children: [_jsxs("div", { children: [_jsx("span", { style: { fontWeight: 'bold' }, children: "ID:" }), " ", item.id ?? '-'] }), _jsxs("div", { children: [_jsx("span", { style: { fontWeight: 'bold' }, children: "DID:" }), " ", item.did ?? '-'] }), _jsxs("div", { children: [_jsx("span", { style: { fontWeight: 'bold' }, children: "TID:" }), " ", item.tid ?? '-'] }), _jsx("hr", {}), _jsxs("div", { children: [_jsxs("span", { style: { fontWeight: 'bold' }, children: [SDKUI_Localizator.Name, ":"] }), " ", item.name ?? '-'] }), _jsxs("div", { children: [_jsxs("span", { style: { fontWeight: 'bold' }, children: [SDKUI_Localizator.Extension, ":"] }), " ", item.ext ?? '-'] }), _jsxs("div", { children: [_jsxs("span", { style: { fontWeight: 'bold' }, children: [SDKUI_Localizator.Author, ":"] }), " ", item.updaterName ?? '-'] }), _jsx("hr", {}), _jsxs("div", { children: [_jsxs("span", { style: { fontWeight: 'bold' }, children: [SDKUI_Localizator.Version, ":"] }), " ", item.version] }), _jsxs("div", { children: [_jsxs("span", { style: { fontWeight: 'bold' }, children: [SDKUI_Localizator.Size, ":"] }), " ", formatBytes(item.size ?? 0)] }), _jsx("hr", {}), _jsxs("div", { children: [_jsxs("span", { style: { fontWeight: 'bold' }, children: [SDKUI_Localizator.CreationTime, ":"] }), " ", Globalization.getDateTimeDisplayValue(item.creationTime)] }), _jsxs("div", { children: [_jsxs("span", { style: { fontWeight: 'bold' }, children: [SDKUI_Localizator.LastUpdateTime, ":"] }), " ", Globalization.getDateTimeDisplayValue(item.lastUpdateTime)] })] }));
66
- return _jsx(TMDcmtIcon, { tid: item.tid, did: item.did, fileExtension: item.ext, downloadMode: 'openInNewWindow', tooltipContent: tooltipContent, isSigned: item.isSigned });
72
+ const tooltipContent = (_jsxs("div", { style: { textAlign: 'left' }, children: [_jsxs("div", { children: [_jsx("span", { style: { fontWeight: 'bold' }, children: "ID:" }), " ", item.id ?? '-'] }), _jsxs("div", { children: [_jsx("span", { style: { fontWeight: 'bold' }, children: "DID:" }), " ", item.did ?? '-'] }), _jsxs("div", { children: [_jsx("span", { style: { fontWeight: 'bold' }, children: "TID:" }), " ", item.tid ?? '-'] }), _jsx("hr", {}), _jsxs("div", { children: [_jsxs("span", { style: { fontWeight: 'bold' }, children: [SDKUI_Localizator.Name, ":"] }), " ", item.name ?? '-'] }), _jsxs("div", { children: [_jsxs("span", { style: { fontWeight: 'bold' }, children: [SDKUI_Localizator.Extension, ":"] }), " ", item.ext ?? '-'] }), _jsxs("div", { children: [_jsxs("span", { style: { fontWeight: 'bold' }, children: [SDKUI_Localizator.Author, ":"] }), " ", item.updaterName ?? '-'] }), _jsx("hr", {}), _jsxs("div", { children: [_jsxs("span", { style: { fontWeight: 'bold' }, children: [SDKUI_Localizator.Version, ":"] }), " ", item.version] }), _jsxs("div", { children: [_jsxs("span", { style: { fontWeight: 'bold' }, children: [SDKUI_Localizator.Size, ":"] }), " ", formatBytes(item.size ?? 0)] }), _jsx("hr", {}), _jsxs("div", { children: [_jsxs("span", { style: { fontWeight: 'bold' }, children: [SDKUI_Localizator.CreationTime, ":"] }), " ", Globalization.getDateTimeDisplayValue(item.creationTime)] }), _jsxs("div", { children: [_jsxs("span", { style: { fontWeight: 'bold' }, children: [SDKUI_Localizator.LastUpdateTime, ":"] }), " ", Globalization.getDateTimeDisplayValue(item.lastUpdateTime)] }), item.description && _jsxs(_Fragment, { children: [_jsx("hr", {}), _jsxs("div", { style: { maxWidth: '400px', overflowWrap: 'anywhere' }, children: [_jsxs("span", { style: { fontWeight: 'bold' }, children: [SDKUI_Localizator.Description, ":"] }), " ", item.description] })] })] }));
73
+ // i link non hanno un file associato: l'icona non deve avviare il download
74
+ const isLink = getFileItemLinkUrl(item) !== undefined;
75
+ return _jsx(TMDcmtIcon, { tid: item.tid, did: item.did, fileExtension: item.ext, downloadMode: isLink ? 'none' : 'openInNewWindow', tooltipContent: tooltipContent, isSigned: item.isSigned });
67
76
  }, []);
68
77
  const cellDatetimeRender = useCallback((cellData) => {
69
78
  if (!cellData.value)
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useCallback, useEffect, useRef } from 'react';
3
- import { colors, TMFileItemContainer } from './TMFileManagerUtils';
3
+ import { colors, getFileItemLinkUrl, TMFileItemContainer } from './TMFileManagerUtils';
4
4
  import { formatBytes, Globalization, renderHighlightedText, SDKUI_Localizator } from '../../helper';
5
5
  import TMTooltip from './TMTooltip';
6
6
  import TMDcmtIcon from '../features/documents/TMDcmtIcon';
@@ -35,6 +35,16 @@ const TMFileManagerThumbnailItems = (props) => {
35
35
  }
36
36
  }
37
37
  }, [items, lastSelectedIndexRef.current]);
38
+ // Apre l'item: i link non hanno un documento da aprire, si apre direttamente l'url in un nuovo tab
39
+ const openFileItem = useCallback((item) => {
40
+ const linkUrl = getFileItemLinkUrl(item);
41
+ if (linkUrl) {
42
+ window.open(linkUrl, '_blank', 'noopener,noreferrer');
43
+ return;
44
+ }
45
+ if (onDoubleClick)
46
+ onDoubleClick(item);
47
+ }, [onDoubleClick]);
38
48
  const handleKeyDown = useCallback((event) => {
39
49
  event.preventDefault();
40
50
  if (event.key === 'ArrowDown' && lastSelectedIndexRef.current !== null) {
@@ -44,21 +54,21 @@ const TMFileManagerThumbnailItems = (props) => {
44
54
  lastSelectedIndexRef.current = currentIndex;
45
55
  }
46
56
  }
47
- if (event.key === 'Enter' && selectedFiles.length === 1 && onDoubleClick) {
57
+ if (event.key === 'Enter' && selectedFiles.length === 1) {
48
58
  const currentItem = items.find(item => item.id === selectedFiles[0].id);
49
59
  if (currentItem)
50
- onDoubleClick(currentItem);
60
+ openFileItem(currentItem);
51
61
  }
52
- }, [items, lastSelectedIndexRef.current, selectedFiles]);
62
+ }, [items, lastSelectedIndexRef.current, selectedFiles, openFileItem]);
53
63
  // Double click handler with timeout cleanup
54
64
  const onDoubleClickHandler = useCallback((item) => {
55
65
  if (clickTimeoutRef.current) {
56
66
  clearTimeout(clickTimeoutRef.current);
57
67
  clickTimeoutRef.current = null;
58
68
  }
59
- if (onDoubleClick && item)
60
- onDoubleClick(item);
61
- }, [onDoubleClick]);
69
+ if (item)
70
+ openFileItem(item);
71
+ }, [openFileItem]);
62
72
  const onClickHandler = useCallback((e, item) => {
63
73
  // If a click timeout is already running, clear it (distinguish between single and double clicks)
64
74
  if (clickTimeoutRef.current) {
@@ -144,8 +154,8 @@ const TMFileManagerThumbnailItems = (props) => {
144
154
  bgHoverColor = isSelected ? colors.PRIMARY_BLUE : "#fff59d";
145
155
  }
146
156
  const editLockTooltipText = _jsxs(_Fragment, { children: [_jsxs("div", { style: { textAlign: "center" }, children: [editMode && (_jsxs(_Fragment, { children: [_jsx("i", { style: { fontSize: "18px", color: colors.MEDIUM_GREEN, fontWeight: "bold" }, className: "dx-icon-edit" }), SDKUI_Localizator.CurrentUserExtract] })), lockMode && (_jsxs(_Fragment, { children: [_jsx("i", { style: { fontSize: "18px", color: colors.MEDIUM_GREEN, fontWeight: "bold" }, className: "dx-icon-lock" }), SDKUI_Localizator.ExtractedFromOtherUser] }))] }), _jsx("hr", {}), _jsxs("div", { style: { textAlign: "left" }, children: [_jsxs("ul", { children: [_jsxs("li", { children: ["- ", _jsx("span", { style: { fontWeight: 'bold' }, children: SDKUI_Localizator.ExtractedBy }), ": ", findCheckOutUserName(item) ?? '-', " (ID: ", item.checkOutUserID, ")"] }), _jsxs("li", { children: ["- ", _jsx("span", { style: { fontWeight: 'bold' }, children: SDKUI_Localizator.ExtractedOn }), ": ", Globalization.getDateTimeDisplayValue(item.checkoutDate?.toString())] })] }), _jsx("hr", {}), _jsx("ul", { children: _jsxs("li", { children: ["- ", _jsx("span", { style: { fontWeight: 'bold' }, children: SDKUI_Localizator.Version }), ": ", item.version ?? 1] }) }), _jsx("hr", {}), _jsxs("ul", { children: [_jsxs("li", { children: ["- ", _jsx("span", { style: { fontWeight: 'bold' }, children: SDKUI_Localizator.Extension }), ": ", item.ext] }), _jsxs("li", { children: ["- ", _jsx("span", { style: { fontWeight: 'bold' }, children: SDKUI_Localizator.CreationTime }), ": ", Globalization.getDateTimeDisplayValue(item.creationTime?.toString())] }), _jsxs("li", { children: ["- ", _jsx("span", { style: { fontWeight: 'bold' }, children: SDKUI_Localizator.LastUpdateTime }), ": ", Globalization.getDateTimeDisplayValue(item.lastUpdateTime?.toString())] })] })] })] });
147
- const tooltipContent = (_jsxs("div", { style: { textAlign: 'left' }, children: [_jsxs("div", { children: [_jsx("span", { style: { fontWeight: 'bold' }, children: "ID:" }), " ", item.id ?? '-'] }), _jsxs("div", { children: [_jsx("span", { style: { fontWeight: 'bold' }, children: "DID:" }), " ", item.did ?? '-'] }), _jsxs("div", { children: [_jsx("span", { style: { fontWeight: 'bold' }, children: "TID:" }), " ", item.tid ?? '-'] }), _jsx("hr", {}), _jsxs("div", { children: [_jsxs("span", { style: { fontWeight: 'bold' }, children: [SDKUI_Localizator.Name, ":"] }), " ", item.name ?? '-'] }), _jsxs("div", { children: [_jsxs("span", { style: { fontWeight: 'bold' }, children: [SDKUI_Localizator.Extension, ":"] }), " ", item.ext ?? '-'] }), _jsxs("div", { children: [_jsxs("span", { style: { fontWeight: 'bold' }, children: [SDKUI_Localizator.Author, ":"] }), " ", item.updaterName ?? '-'] }), _jsx("hr", {}), _jsxs("div", { children: [_jsxs("span", { style: { fontWeight: 'bold' }, children: [SDKUI_Localizator.Version, ":"] }), " ", item.version] }), _jsxs("div", { children: [_jsxs("span", { style: { fontWeight: 'bold' }, children: [SDKUI_Localizator.Size, ":"] }), " ", formatBytes(item.size ?? 0)] }), _jsx("hr", {}), _jsxs("div", { children: [_jsxs("span", { style: { fontWeight: 'bold' }, children: [SDKUI_Localizator.CreationTime, ":"] }), " ", Globalization.getDateTimeDisplayValue(item.creationTime)] }), _jsxs("div", { children: [_jsxs("span", { style: { fontWeight: 'bold' }, children: [SDKUI_Localizator.LastUpdateTime, ":"] }), " ", Globalization.getDateTimeDisplayValue(item.lastUpdateTime)] })] }));
148
- return _jsx(TMFileItemContainer, { className: "tm-file-manager-thumbnail-items", ref: containerRef, id: "tm-file-manager-thumbnail-item-" + item.id.toString(), "$backgroundColor": bgColor, "$bgHoverColor": bgHoverColor, "$textColor": textColor, onDoubleClick: () => onDoubleClickHandler(item), onContextMenu: (e) => onContextMenu(e, item), onClick: (e) => onClickHandler(e, item), tabIndex: 0, onKeyDown: handleKeyDown, onKeyUp: handleKeyUp, children: _jsxs("div", { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', width: '100%' }, children: [_jsxs("div", { style: { display: 'flex', alignItems: 'center', flex: 1, minWidth: 0 }, children: [_jsxs("div", { style: { marginRight: '16px', flexShrink: 0, display: 'flex', flexDirection: 'column', alignItems: 'center' }, children: [_jsx("div", { style: { width: '40px' }, children: _jsx(TMDcmtIcon, { tid: item.tid, did: item.did, fileExtension: item.ext, downloadMode: 'openInNewWindow', tooltipContent: tooltipContent, isSigned: item.isSigned }) }), _jsxs("div", { style: { display: 'flex', justifyContent: 'center', width: '40px' }, children: [editMode && _jsx(TMTooltip, { content: editLockTooltipText, children: _jsx("i", { style: { fontSize: "18px", color: !isSelected ? colors.MEDIUM_GREEN : '#fff', fontWeight: "bold" }, className: "dx-icon-edit" }) }), lockMode && _jsx(TMTooltip, { content: editLockTooltipText, children: _jsx("i", { style: { fontSize: "18px", color: !isSelected ? colors.MEDIUM_GREEN : '#fff', fontWeight: "bold" }, className: "dx-icon-lock" }) })] })] }), _jsxs("div", { style: { overflow: 'hidden', minWidth: 0 }, children: [_jsx("div", { style: { whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', width: '100%', display: 'block', fontSize: '1rem', fontWeight: "bold" }, children: _jsx(TMTooltip, { parentStyle: { overflow: 'hidden' }, childStyle: { whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', width: '100%', display: 'block' }, children: renderHighlightedText(item.name, searchText, isSelected) }) }), _jsx("div", { style: { whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', width: '100%', display: 'block', fontSize: 'calc(1rem - 1px)' }, children: formatBytes(item.size ?? 0) })] })] }), item.version && (_jsx("div", { style: { flexShrink: 0, marginLeft: '12px', whiteSpace: 'nowrap' }, children: _jsx(TMTooltip, { content: SDKUI_Localizator.Version, children: _jsx("div", { style: { border: "2px solid #28a745", backgroundColor: "#28a745", color: "#ffffff", borderRadius: '50%', width: '30px', height: '30px', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: '12px', fontWeight: 'bold' }, children: item.version }) }) }))] }) }, "tm-file-manager-thumbnail-item-" + item.id);
157
+ const tooltipContent = (_jsxs("div", { style: { textAlign: 'left' }, children: [_jsxs("div", { children: [_jsx("span", { style: { fontWeight: 'bold' }, children: "ID:" }), " ", item.id ?? '-'] }), _jsxs("div", { children: [_jsx("span", { style: { fontWeight: 'bold' }, children: "DID:" }), " ", item.did ?? '-'] }), _jsxs("div", { children: [_jsx("span", { style: { fontWeight: 'bold' }, children: "TID:" }), " ", item.tid ?? '-'] }), _jsx("hr", {}), _jsxs("div", { children: [_jsxs("span", { style: { fontWeight: 'bold' }, children: [SDKUI_Localizator.Name, ":"] }), " ", item.name ?? '-'] }), _jsxs("div", { children: [_jsxs("span", { style: { fontWeight: 'bold' }, children: [SDKUI_Localizator.Extension, ":"] }), " ", item.ext ?? '-'] }), _jsxs("div", { children: [_jsxs("span", { style: { fontWeight: 'bold' }, children: [SDKUI_Localizator.Author, ":"] }), " ", item.updaterName ?? '-'] }), _jsx("hr", {}), _jsxs("div", { children: [_jsxs("span", { style: { fontWeight: 'bold' }, children: [SDKUI_Localizator.Version, ":"] }), " ", item.version] }), _jsxs("div", { children: [_jsxs("span", { style: { fontWeight: 'bold' }, children: [SDKUI_Localizator.Size, ":"] }), " ", formatBytes(item.size ?? 0)] }), _jsx("hr", {}), _jsxs("div", { children: [_jsxs("span", { style: { fontWeight: 'bold' }, children: [SDKUI_Localizator.CreationTime, ":"] }), " ", Globalization.getDateTimeDisplayValue(item.creationTime)] }), _jsxs("div", { children: [_jsxs("span", { style: { fontWeight: 'bold' }, children: [SDKUI_Localizator.LastUpdateTime, ":"] }), " ", Globalization.getDateTimeDisplayValue(item.lastUpdateTime)] }), item.description && _jsxs(_Fragment, { children: [_jsx("hr", {}), _jsxs("div", { style: { maxWidth: '400px', overflowWrap: 'anywhere' }, children: [_jsxs("span", { style: { fontWeight: 'bold' }, children: [SDKUI_Localizator.Description, ":"] }), " ", item.description] })] })] }));
158
+ return _jsx(TMFileItemContainer, { className: "tm-file-manager-thumbnail-items", ref: containerRef, id: "tm-file-manager-thumbnail-item-" + item.id.toString(), "$backgroundColor": bgColor, "$bgHoverColor": bgHoverColor, "$textColor": textColor, onDoubleClick: () => onDoubleClickHandler(item), onContextMenu: (e) => onContextMenu(e, item), onClick: (e) => onClickHandler(e, item), tabIndex: 0, onKeyDown: handleKeyDown, onKeyUp: handleKeyUp, children: _jsxs("div", { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', width: '100%' }, children: [_jsxs("div", { style: { display: 'flex', alignItems: 'center', flex: 1, minWidth: 0 }, children: [_jsxs("div", { style: { marginRight: '16px', flexShrink: 0, display: 'flex', flexDirection: 'column', alignItems: 'center' }, children: [_jsx("div", { style: { width: '40px' }, children: _jsx(TMDcmtIcon, { tid: item.tid, did: item.did, fileExtension: item.ext, downloadMode: getFileItemLinkUrl(item) !== undefined ? 'none' : 'openInNewWindow', tooltipContent: tooltipContent, isSigned: item.isSigned }) }), _jsxs("div", { style: { display: 'flex', justifyContent: 'center', width: '40px' }, children: [editMode && _jsx(TMTooltip, { content: editLockTooltipText, children: _jsx("i", { style: { fontSize: "18px", color: !isSelected ? colors.MEDIUM_GREEN : '#fff', fontWeight: "bold" }, className: "dx-icon-edit" }) }), lockMode && _jsx(TMTooltip, { content: editLockTooltipText, children: _jsx("i", { style: { fontSize: "18px", color: !isSelected ? colors.MEDIUM_GREEN : '#fff', fontWeight: "bold" }, className: "dx-icon-lock" }) })] })] }), _jsxs("div", { style: { overflow: 'hidden', minWidth: 0 }, children: [_jsx("div", { style: { whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', width: '100%', display: 'block', fontSize: '1rem', fontWeight: "bold" }, children: _jsx(TMTooltip, { parentStyle: { overflow: 'hidden' }, childStyle: { whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', width: '100%', display: 'block' }, children: renderHighlightedText(item.name, searchText, isSelected) }) }), _jsx("div", { style: { whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', width: '100%', display: 'block', fontSize: 'calc(1rem - 1px)' }, children: formatBytes(item.size ?? 0) })] })] }), item.version && (_jsx("div", { style: { flexShrink: 0, marginLeft: '12px', whiteSpace: 'nowrap' }, children: _jsx(TMTooltip, { content: SDKUI_Localizator.Version, children: _jsx("div", { style: { border: "2px solid #28a745", backgroundColor: "#28a745", color: "#ffffff", borderRadius: '50%', width: '30px', height: '30px', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: '12px', fontWeight: 'bold' }, children: item.version }) }) }))] }) }, "tm-file-manager-thumbnail-item-" + item.id);
149
159
  }) });
150
160
  };
151
161
  export default TMFileManagerThumbnailItems;
@@ -26,6 +26,7 @@ export interface FileItem {
26
26
  version?: number;
27
27
  isSigned?: number;
28
28
  }
29
+ export declare const resolveFileItemUserNames: (item: FileItem, users: Array<UserDescriptor>) => FileItem;
29
30
  export interface TMFileManagerTreeViewDirectory {
30
31
  id: number;
31
32
  text: string;
@@ -56,6 +57,7 @@ export declare const TMFileItemContainer: import("styled-components/dist/types")
56
57
  $textColor?: string;
57
58
  $bgHoverColor?: string;
58
59
  }, never>>> & string;
60
+ export declare const getFileItemLinkUrl: (fileItem: FileItem | undefined) => string | undefined;
59
61
  export declare const findFileItems: (items: Array<FileItem>, id: number) => FileItem | undefined;
60
62
  export declare const setFolderTreeViewItems: (items: Array<FileItem>) => Array<TMFileManagerTreeViewDirectory>;
61
63
  export declare const buildFolderHierarchy: (fileSystemTree: WGTreeDescriptor | undefined, draftsFile: SearchResultDescriptor | undefined, archivedDocuments: Array<SearchResultDescriptor> | undefined, participants: Array<UserDescriptor> | undefined) => {
@@ -1,5 +1,5 @@
1
1
  import styled from "styled-components";
2
- import { associateColumnsToRows, SIGNATURE_EXTENSIONS } from "../../helper";
2
+ import { associateColumnsToRows, SIGNATURE_EXTENSIONS, WHATS_NEWS_FILE_NAME, WHATS_NEWS_LINK_URL } from "../../helper";
3
3
  /**
4
4
  * Verifica se un'estensione indica che il file è firmato digitalmente.
5
5
  * Controlla se l'estensione (es. "pdf.p7m", ".p7m", "p7m") contiene
@@ -12,6 +12,22 @@ export const isSigned = (ext) => {
12
12
  const parts = normalized.split('.');
13
13
  return parts.some(part => SIGNATURE_EXTENSIONS.has(part));
14
14
  };
15
+ // Completa i nomi utente (autore e utente di check-out) di un FileItem quando mancano, risolvendoli dagli ID.
16
+ export const resolveFileItemUserNames = (item, users) => {
17
+ if (!users || users.length === 0)
18
+ return item;
19
+ const isValidUserID = (id) => id !== undefined && Number.isFinite(id) && id > 0;
20
+ const needsUpdaterName = !item.updaterName && isValidUserID(item.updaterID);
21
+ const needsCheckOutUserName = !item.checkOutUserName && isValidUserID(item.checkOutUserID);
22
+ if (!needsUpdaterName && !needsCheckOutUserName)
23
+ return item;
24
+ const resolved = { ...item };
25
+ if (needsUpdaterName)
26
+ resolved.updaterName = users.find(user => user.id === item.updaterID)?.name ?? item.updaterName;
27
+ if (needsCheckOutUserName)
28
+ resolved.checkOutUserName = users.find(user => user.id === item.checkOutUserID)?.name ?? item.checkOutUserName;
29
+ return resolved;
30
+ };
15
31
  export var TMFileManagerPageSize;
16
32
  (function (TMFileManagerPageSize) {
17
33
  TMFileManagerPageSize[TMFileManagerPageSize["Small"] = 30] = "Small";
@@ -47,6 +63,26 @@ export const TMFileItemContainer = styled.div `
47
63
  outline: none;
48
64
  }
49
65
  `;
66
+ // Confronto case-insensitive con il nome del file
67
+ const isWhatsNewsFileName = (name) => (name ?? '').toLowerCase() === WHATS_NEWS_FILE_NAME;
68
+ // Ritorna l'url del link associato al file: un file il cui metadato "description" contiene un url http/https
69
+ // e' un link, quindi non ha un file/documento da scaricare o da aprire nella form: si apre direttamente l'url
70
+ export const getFileItemLinkUrl = (fileItem) => {
71
+ if (!fileItem || fileItem.isDirectory)
72
+ return undefined;
73
+ if (isWhatsNewsFileName(fileItem.name))
74
+ return WHATS_NEWS_LINK_URL;
75
+ const value = fileItem.description?.trim();
76
+ if (!value)
77
+ return undefined;
78
+ try {
79
+ const url = new URL(value);
80
+ return (url.protocol === 'http:' || url.protocol === 'https:') ? url.href : undefined;
81
+ }
82
+ catch {
83
+ return undefined;
84
+ }
85
+ };
50
86
  // Function to find a specific file or folder based on its ID (used for finding nested items)
51
87
  export const findFileItems = (items, id) => {
52
88
  for (let item of items) {