@topconsultnpm/sdkui-react 6.20.0-dev1.13 → 6.20.0-dev1.131

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 (202) hide show
  1. package/lib/assets/Toppy-help-center.png +0 -0
  2. package/lib/assets/headergradient.svg +87 -0
  3. package/lib/components/NewComponents/ContextMenu/TMContextMenu.js +322 -30
  4. package/lib/components/NewComponents/ContextMenu/hooks.d.ts +8 -1
  5. package/lib/components/NewComponents/ContextMenu/hooks.js +80 -8
  6. package/lib/components/NewComponents/ContextMenu/index.d.ts +3 -0
  7. package/lib/components/NewComponents/ContextMenu/index.js +2 -0
  8. package/lib/components/NewComponents/ContextMenu/styles.d.ts +9 -1
  9. package/lib/components/NewComponents/ContextMenu/styles.js +146 -47
  10. package/lib/components/NewComponents/ContextMenu/types.d.ts +22 -3
  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.js +620 -125
  14. package/lib/components/NewComponents/FloatingMenuBar/styles.d.ts +25 -5
  15. package/lib/components/NewComponents/FloatingMenuBar/styles.js +215 -59
  16. package/lib/components/NewComponents/FloatingMenuBar/types.d.ts +12 -3
  17. package/lib/components/base/TMAccordionNew.js +35 -14
  18. package/lib/components/base/TMButton.js +6 -0
  19. package/lib/components/base/TMClosableList.js +4 -0
  20. package/lib/components/base/TMCustomButton.js +61 -17
  21. package/lib/components/base/TMDataGrid.d.ts +7 -4
  22. package/lib/components/base/TMDataGrid.js +153 -11
  23. package/lib/components/base/TMDropDownMenu.js +21 -18
  24. package/lib/components/base/TMFileManager.d.ts +4 -3
  25. package/lib/components/base/TMFileManager.js +32 -24
  26. package/lib/components/base/TMFileManagerDataGridView.d.ts +3 -2
  27. package/lib/components/base/TMFileManagerDataGridView.js +1 -11
  28. package/lib/components/base/TMFileManagerThumbnailItems.d.ts +7 -1
  29. package/lib/components/base/TMFileManagerThumbnailItems.js +5 -2
  30. package/lib/components/base/TMFileManagerThumbnailsView.d.ts +17 -4
  31. package/lib/components/base/TMFileManagerThumbnailsView.js +18 -6
  32. package/lib/components/base/TMFileManagerUtils.d.ts +0 -12
  33. package/lib/components/base/TMListView.js +33 -15
  34. package/lib/components/base/TMPanel.d.ts +1 -1
  35. package/lib/components/base/TMPanel.js +4 -2
  36. package/lib/components/base/TMPopUp.js +6 -0
  37. package/lib/components/base/TMToolbarCard.js +2 -0
  38. package/lib/components/base/TMTreeView.d.ts +2 -1
  39. package/lib/components/base/TMTreeView.js +33 -26
  40. package/lib/components/choosers/TMDataListItemChooser.d.ts +2 -0
  41. package/lib/components/choosers/TMDataListItemChooser.js +8 -2
  42. package/lib/components/choosers/TMDcmtTypeChooser.d.ts +1 -0
  43. package/lib/components/choosers/TMDcmtTypeChooser.js +11 -3
  44. package/lib/components/choosers/TMDistinctValues.js +2 -2
  45. package/lib/components/choosers/TMDynDataListItemChooser.d.ts +2 -0
  46. package/lib/components/choosers/TMDynDataListItemChooser.js +8 -2
  47. package/lib/components/choosers/TMInvoiceRetrieveFormats.js +1 -1
  48. package/lib/components/choosers/TMMetadataChooser.d.ts +2 -0
  49. package/lib/components/choosers/TMMetadataChooser.js +19 -4
  50. package/lib/components/choosers/TMOrderRetrieveFormats.js +1 -1
  51. package/lib/components/choosers/TMUserChooser.d.ts +2 -5
  52. package/lib/components/choosers/TMUserChooser.js +33 -47
  53. package/lib/components/editors/TMCheckBox.js +2 -0
  54. package/lib/components/editors/TMDateBox.js +18 -9
  55. package/lib/components/editors/TMEditorStyled.js +7 -0
  56. package/lib/components/editors/TMLocalizedTextBox.d.ts +3 -1
  57. package/lib/components/editors/TMLocalizedTextBox.js +16 -14
  58. package/lib/components/editors/TMMetadataEditor.d.ts +1 -0
  59. package/lib/components/editors/TMMetadataEditor.js +4 -4
  60. package/lib/components/editors/TMMetadataTextBox.d.ts +9 -0
  61. package/lib/components/editors/TMMetadataTextBox.js +92 -0
  62. package/lib/components/editors/TMMetadataValues.d.ts +2 -0
  63. package/lib/components/editors/TMMetadataValues.js +26 -8
  64. package/lib/components/editors/TMRadioButton.js +2 -0
  65. package/lib/components/editors/TMTextArea.js +18 -30
  66. package/lib/components/editors/TMTextBox.d.ts +1 -1
  67. package/lib/components/editors/TMTextBox.js +29 -4
  68. package/lib/components/editors/TMTextExpression.js +6 -91
  69. package/lib/components/features/archive/TMArchive.js +2 -2
  70. package/lib/components/features/assistant/TMToppyDraggableHelpCenter.d.ts +15 -0
  71. package/lib/components/features/assistant/TMToppyDraggableHelpCenter.js +462 -0
  72. package/lib/components/features/assistant/TMToppySpeechBubble.d.ts +11 -0
  73. package/lib/components/features/assistant/TMToppySpeechBubble.js +126 -0
  74. package/lib/components/features/documents/TMDcmtBlog.js +1 -1
  75. package/lib/components/features/documents/TMDcmtForm.d.ts +14 -2
  76. package/lib/components/features/documents/TMDcmtForm.js +576 -292
  77. package/lib/components/features/documents/TMDcmtPreview.js +42 -155
  78. package/lib/components/features/documents/TMDcmtTasks.js +9 -9
  79. package/lib/components/features/documents/TMMasterDetailDcmts.js +38 -53
  80. package/lib/components/features/documents/TMRelationViewer.d.ts +1 -1
  81. package/lib/components/features/documents/TMRelationViewer.js +2 -2
  82. package/lib/components/features/search/TMDcmtCheckoutInfoForm.d.ts +8 -0
  83. package/lib/components/features/search/{TMSearchResultCheckoutInfoForm.js → TMDcmtCheckoutInfoForm.js} +2 -2
  84. package/lib/components/features/search/TMSavedQuerySelector.js +72 -67
  85. package/lib/components/features/search/TMSearch.d.ts +3 -0
  86. package/lib/components/features/search/TMSearch.js +50 -11
  87. package/lib/components/features/search/TMSearchQueryEditor.d.ts +1 -0
  88. package/lib/components/features/search/TMSearchQueryEditor.js +10 -10
  89. package/lib/components/features/search/TMSearchQueryPanel.d.ts +1 -0
  90. package/lib/components/features/search/TMSearchQueryPanel.js +40 -25
  91. package/lib/components/features/search/TMSearchResult.d.ts +3 -0
  92. package/lib/components/features/search/TMSearchResult.js +370 -252
  93. package/lib/components/features/search/TMSearchResultsMenuItems.d.ts +3 -3
  94. package/lib/components/features/search/TMSearchResultsMenuItems.js +227 -171
  95. package/lib/components/features/search/TMSignSettingsForm.js +1 -1
  96. package/lib/components/features/search/TMSignatureInfoContent.d.ts +6 -0
  97. package/lib/components/features/search/TMSignatureInfoContent.js +140 -0
  98. package/lib/components/features/search/TMViewHistoryDcmt.js +47 -52
  99. package/lib/components/features/tasks/TMTaskForm.js +75 -25
  100. package/lib/components/features/tasks/TMTasksAgenda.d.ts +3 -1
  101. package/lib/components/features/tasks/TMTasksAgenda.js +48 -9
  102. package/lib/components/features/tasks/TMTasksCalendar.d.ts +2 -0
  103. package/lib/components/features/tasks/TMTasksCalendar.js +19 -7
  104. package/lib/components/features/tasks/TMTasksUtils.d.ts +2 -2
  105. package/lib/components/features/tasks/TMTasksUtils.js +57 -37
  106. package/lib/components/features/tasks/TMTasksView.js +28 -19
  107. package/lib/components/features/workflow/TMWorkflowPopup.d.ts +33 -2
  108. package/lib/components/features/workflow/TMWorkflowPopup.js +140 -34
  109. package/lib/components/features/workflow/diagram/DiagramItemComponent.d.ts +2 -0
  110. package/lib/components/features/workflow/diagram/DiagramItemComponent.js +14 -7
  111. package/lib/components/features/workflow/diagram/DiagramItemForm.js +1 -1
  112. package/lib/components/features/workflow/diagram/RecipientList.js +3 -2
  113. package/lib/components/features/workflow/diagram/WFDiagram.d.ts +4 -0
  114. package/lib/components/features/workflow/diagram/WFDiagram.js +164 -13
  115. package/lib/components/forms/Login/LoginValidatorService.d.ts +2 -0
  116. package/lib/components/forms/Login/LoginValidatorService.js +7 -2
  117. package/lib/components/forms/Login/TMLoginForm.js +35 -7
  118. package/lib/components/forms/TMChooserForm.js +1 -1
  119. package/lib/components/grids/TMBlogsPost.js +56 -31
  120. package/lib/components/grids/TMRecentsManager.js +20 -10
  121. package/lib/components/grids/TMValidationItemsList.js +6 -0
  122. package/lib/components/index.d.ts +6 -3
  123. package/lib/components/index.js +6 -3
  124. package/lib/components/layout/panelManager/TMPanelManagerContext.js +13 -5
  125. package/lib/components/query/TMQueryEditor.d.ts +6 -1
  126. package/lib/components/query/TMQueryEditor.js +105 -101
  127. package/lib/components/settings/SettingsAppearance.d.ts +2 -1
  128. package/lib/components/settings/SettingsAppearance.js +99 -30
  129. package/lib/components/sidebar/TMHeader.js +11 -7
  130. package/lib/components/sidebar/TMSidebar.d.ts +0 -1
  131. package/lib/components/sidebar/TMSidebar.js +16 -44
  132. package/lib/components/sidebar/TMSidebarItem.js +36 -17
  133. package/lib/components/viewers/TMDataListItemViewer.d.ts +2 -1
  134. package/lib/components/viewers/TMDataListItemViewer.js +35 -71
  135. package/lib/components/viewers/TMDataUserIdItemViewer.d.ts +8 -0
  136. package/lib/components/viewers/TMDataUserIdItemViewer.js +39 -0
  137. package/lib/css/tm-sdkui.css +1 -1
  138. package/lib/helper/SDKUI_Globals.d.ts +22 -0
  139. package/lib/helper/SDKUI_Globals.js +10 -1
  140. package/lib/helper/SDKUI_Localizator.d.ts +21 -3
  141. package/lib/helper/SDKUI_Localizator.js +196 -10
  142. package/lib/helper/TMCommandsContextMenu.d.ts +4 -2
  143. package/lib/helper/TMCommandsContextMenu.js +15 -4
  144. package/lib/helper/TMIcons.d.ts +4 -0
  145. package/lib/helper/TMIcons.js +13 -3
  146. package/lib/helper/TMPdfViewer.d.ts +8 -0
  147. package/lib/helper/TMPdfViewer.js +373 -0
  148. package/lib/helper/TMToppyMessage.js +4 -0
  149. package/lib/helper/checkinCheckoutManager.d.ts +31 -1
  150. package/lib/helper/checkinCheckoutManager.js +112 -30
  151. package/lib/helper/devextremeCustomMessages.d.ts +30 -0
  152. package/lib/helper/devextremeCustomMessages.js +30 -0
  153. package/lib/helper/helpers.d.ts +30 -2
  154. package/lib/helper/helpers.js +132 -4
  155. package/lib/helper/index.d.ts +2 -0
  156. package/lib/helper/index.js +2 -0
  157. package/lib/helper/queryHelper.d.ts +2 -2
  158. package/lib/helper/queryHelper.js +80 -24
  159. package/lib/helper/workItemsHelper.d.ts +6 -0
  160. package/lib/helper/workItemsHelper.js +230 -0
  161. package/lib/hooks/useCheckInOutOperations.d.ts +28 -0
  162. package/lib/hooks/useCheckInOutOperations.js +223 -0
  163. package/lib/hooks/useDataListItem.d.ts +12 -0
  164. package/lib/hooks/useDataListItem.js +132 -0
  165. package/lib/hooks/useDataUserIdItem.d.ts +10 -0
  166. package/lib/hooks/useDataUserIdItem.js +96 -0
  167. package/lib/hooks/useFloatingBarPinnedItems.d.ts +11 -0
  168. package/lib/hooks/useFloatingBarPinnedItems.js +54 -0
  169. package/lib/hooks/useMetadataExpression.d.ts +19 -0
  170. package/lib/hooks/useMetadataExpression.js +99 -0
  171. package/lib/hooks/useSettingsFeedback.d.ts +11 -0
  172. package/lib/hooks/useSettingsFeedback.js +38 -0
  173. package/lib/hooks/useWorkflowApprove.d.ts +4 -0
  174. package/lib/hooks/useWorkflowApprove.js +14 -1
  175. package/lib/index.d.ts +1 -0
  176. package/lib/index.js +3 -2
  177. package/lib/services/platform_services.d.ts +3 -3
  178. package/lib/ts/types.d.ts +61 -1
  179. package/lib/utils/theme.d.ts +1 -1
  180. package/lib/utils/theme.js +1 -1
  181. package/package.json +8 -6
  182. package/lib/components/NewComponents/Notification/Notification.d.ts +0 -4
  183. package/lib/components/NewComponents/Notification/Notification.js +0 -60
  184. package/lib/components/NewComponents/Notification/NotificationContainer.d.ts +0 -8
  185. package/lib/components/NewComponents/Notification/NotificationContainer.js +0 -33
  186. package/lib/components/NewComponents/Notification/index.d.ts +0 -2
  187. package/lib/components/NewComponents/Notification/index.js +0 -2
  188. package/lib/components/NewComponents/Notification/styles.d.ts +0 -21
  189. package/lib/components/NewComponents/Notification/styles.js +0 -180
  190. package/lib/components/NewComponents/Notification/types.d.ts +0 -18
  191. package/lib/components/NewComponents/Notification/types.js +0 -1
  192. package/lib/components/base/TMContextMenu.d.ts +0 -25
  193. package/lib/components/base/TMContextMenu.js +0 -109
  194. package/lib/components/base/TMContextMenuOLD.d.ts +0 -26
  195. package/lib/components/base/TMContextMenuOLD.js +0 -56
  196. package/lib/components/base/TMFloatingToolbar.d.ts +0 -9
  197. package/lib/components/base/TMFloatingToolbar.js +0 -101
  198. package/lib/components/features/assistant/ToppyDraggableHelpCenter.d.ts +0 -30
  199. package/lib/components/features/assistant/ToppyDraggableHelpCenter.js +0 -482
  200. package/lib/components/features/assistant/ToppySpeechBubble.d.ts +0 -9
  201. package/lib/components/features/assistant/ToppySpeechBubble.js +0 -117
  202. package/lib/components/features/search/TMSearchResultCheckoutInfoForm.d.ts +0 -8
@@ -0,0 +1,373 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useState, useRef, useCallback } from "react";
3
+ import styled from "styled-components";
4
+ import { LoadIndicator } from 'devextreme-react/load-indicator';
5
+ import { IconCloseOutline } from "./TMIcons";
6
+ import { SDKUI_Localizator } from "./SDKUI_Localizator";
7
+ import { TMColors } from "../utils/theme";
8
+ import { TMMessageBoxManager, ButtonNames } from "../components/base/TMPopUp";
9
+ // Dynamic imports for optional dependencies
10
+ let pdfjs;
11
+ let Document;
12
+ let Page;
13
+ let isReactPdfAvailable = false;
14
+ try {
15
+ const reactPdf = require('react-pdf');
16
+ pdfjs = reactPdf.pdfjs;
17
+ Document = reactPdf.Document;
18
+ Page = reactPdf.Page;
19
+ // Configura il worker PDF.js PRIMA del rendering
20
+ pdfjs.GlobalWorkerOptions.workerSrc = `https://unpkg.com/pdfjs-dist@${pdfjs.version}/build/pdf.worker.min.mjs`;
21
+ isReactPdfAvailable = true;
22
+ }
23
+ catch (error) {
24
+ // react-pdf not available - will use iframe fallback
25
+ // console.warn('react-pdf is not installed. TMPdfViewer will use iframe fallback.');
26
+ }
27
+ const PDFViewerContainer = styled.div `
28
+ width: 100%;
29
+ height: 100%;
30
+ overflow-y: auto;
31
+ overflow-x: hidden;
32
+ background-color: #f5f5f5;
33
+ position: relative;
34
+
35
+ .react-pdf__Document {
36
+ display: flex;
37
+ flex-direction: column;
38
+ align-items: center;
39
+ gap: 10px;
40
+ padding: 10px 0;
41
+ }
42
+
43
+ .react-pdf__Page {
44
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
45
+ margin: 0 auto;
46
+ }
47
+
48
+ .react-pdf__Page__canvas {
49
+ max-width: 100%;
50
+ height: auto !important;
51
+ }
52
+ `;
53
+ const LoadingOverlay = styled.div `
54
+ position: absolute;
55
+ top: 0;
56
+ left: 0;
57
+ width: 100%;
58
+ height: 100%;
59
+ background-color: rgba(245, 245, 245, 0.95);
60
+ display: flex;
61
+ justify-content: center;
62
+ align-items: center;
63
+ z-index: 1000;
64
+ `;
65
+ const TMPdfViewer = (props) => {
66
+ const { pdfBlob, title = "Anteprima PDF", isResizingActive, enableFitToWidth = false } = props;
67
+ const [isMobile, setIsMobile] = useState(false);
68
+ const [totalPagesNumber, setTotalPagesNumber] = useState(0);
69
+ const [loadedPagesNumber, setLoadedPagesNumber] = useState(0);
70
+ const [visiblePages, setVisiblePages] = useState(new Set([1]));
71
+ const [pdfUrl, setPdfUrl] = useState("");
72
+ const [hasUnsafeContent, setHasUnsafeContent] = useState(false);
73
+ const [isCheckingPdf, setIsCheckingPdf] = useState(true);
74
+ const [jsMatches, setJsMatches] = useState([]);
75
+ const observerRef = useRef(null);
76
+ useEffect(() => {
77
+ const checkIsMobile = () => {
78
+ try {
79
+ const userAgent = navigator.userAgent || window.opera;
80
+ // Detect actual mobile/tablet devices
81
+ const isMobileDevice =
82
+ // User agent detection (phones and tablets)
83
+ /android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini/i.test(userAgent) ||
84
+ // Media query for touch devices with coarse pointer (more reliable than screen width)
85
+ (window.matchMedia?.('(hover: none) and (pointer: coarse)').matches ?? false) ||
86
+ // Touch-capable devices excluding desktop OS
87
+ (navigator.maxTouchPoints > 1 && !/Win|Mac|Linux x86_64/i.test(userAgent));
88
+ setIsMobile(isMobileDevice);
89
+ }
90
+ catch (error) {
91
+ setIsMobile(false);
92
+ }
93
+ };
94
+ const checkPdfForJavaScript = async () => {
95
+ setIsCheckingPdf(true);
96
+ try {
97
+ // Legge il PDF come testo per cercare pattern di JavaScript
98
+ const arrayBuffer = await pdfBlob.arrayBuffer();
99
+ const uint8Array = new Uint8Array(arrayBuffer);
100
+ const text = new TextDecoder('latin1').decode(uint8Array);
101
+ // Pattern specifici per rilevare JavaScript effettivo nelle strutture PDF
102
+ const jsPatterns = [
103
+ // Esempio: /JavaScript [ (app.alert('Hello');) ]
104
+ { name: 'JavaScript Dictionary Entry', pattern: /\/JavaScript\s*[(\[<][\s\S]*?[)\]>]/i },
105
+ // Esempio: /JS 15 0 R (riferimento a un oggetto JavaScript)
106
+ { name: 'JavaScript Object Reference', pattern: /\/JS\s+\d+\s+\d+\s+R/i },
107
+ // Esempio: /JS (app.alert('Click');) o /JS <hexstring>
108
+ { name: 'Inline JavaScript Code', pattern: /\/JS\s*[(<][\s\S]*?[)>]/i },
109
+ // Esempio: /AA << /O << /S /JavaScript /JS (app.alert('Open');) >> >>
110
+ { name: 'Additional Actions (AA) with JavaScript', pattern: /\/AA\s*<<[\s\S]*?\/JS[\s\S]*?>>/is },
111
+ // Esempio: /OpenAction << /S /JavaScript /JS (this.print();) >>
112
+ { name: 'Document Open Action with JavaScript', pattern: /\/OpenAction\s*<<[\s\S]*?\/JS[\s\S]*?>>/is },
113
+ // Esempio: /Names << /JavaScript [ (MyScript) 12 0 R ] >>
114
+ { name: 'Named JavaScript Functions', pattern: /\/Names\s*<<[\s\S]*?\/JavaScript[\s\S]*?>>/is },
115
+ ];
116
+ let foundJS = false;
117
+ const matches = [];
118
+ jsPatterns.forEach(({ name, pattern }) => {
119
+ const match = text.match(pattern);
120
+ if (match) {
121
+ foundJS = true;
122
+ const matchIndex = match.index || 0;
123
+ const contextStart = Math.max(0, matchIndex - 50);
124
+ const contextEnd = Math.min(text.length, matchIndex + match[0].length + 50);
125
+ const context = text.substring(contextStart, contextEnd);
126
+ matches.push({
127
+ name,
128
+ pattern: pattern.toString(),
129
+ match: match[0],
130
+ context: context.replace(/[\r\n]+/g, ' ').trim()
131
+ });
132
+ }
133
+ });
134
+ setHasUnsafeContent(foundJS);
135
+ setJsMatches(matches);
136
+ }
137
+ catch (error) {
138
+ // console.error('Errore nella validazione del PDF:', error);
139
+ // In caso di errore, permetti la visualizzazione
140
+ setHasUnsafeContent(false);
141
+ }
142
+ finally {
143
+ setIsCheckingPdf(false);
144
+ }
145
+ };
146
+ checkIsMobile();
147
+ checkPdfForJavaScript();
148
+ // Create URL for iframe
149
+ const url = URL.createObjectURL(pdfBlob);
150
+ setPdfUrl(url);
151
+ return () => {
152
+ if (url) {
153
+ URL.revokeObjectURL(url);
154
+ }
155
+ };
156
+ }, [pdfBlob]);
157
+ /**
158
+ * Callback per l'Intersection Observer che gestisce il lazy loading delle pagine PDF.
159
+ * Viene chiamato ogni volta che una pagina entra o esce dal viewport (area visibile).
160
+ *
161
+ * - Monitora quando gli elementi (pagine) diventano visibili
162
+ * - Aggiunge il numero di pagina al Set delle pagine visibili quando entra nel viewport
163
+ * - Il rootMargin di 500px carica le pagine prima che siano effettivamente visibili (preloading)
164
+ */
165
+ const pageObserverCallback = useCallback((entries) => {
166
+ entries.forEach(entry => {
167
+ const pageNum = parseInt(entry.target.getAttribute('data-page-number') || '0');
168
+ if (entry.isIntersecting) {
169
+ // Aggiunge la pagina al Set di quelle da renderizzare
170
+ setVisiblePages(prev => new Set([...prev, pageNum]));
171
+ }
172
+ });
173
+ }, []);
174
+ /**
175
+ * Crea e configura l'Intersection Observer per il lazy loading.
176
+ *
177
+ * Configurazione:
178
+ * - root: null → osserva rispetto al viewport del browser
179
+ * - rootMargin: '500px' → inizia il caricamento 500px prima che la pagina sia visibile (buffer)
180
+ * - threshold: 0.01 → trigger quando anche solo l'1% dell'elemento è visibile
181
+ *
182
+ * Benefici:
183
+ * - Non blocca l'UI durante il rendering
184
+ * - Carica solo le pagine necessarie
185
+ * - Migliora le performance su PDF con molte pagine
186
+ */
187
+ useEffect(() => {
188
+ observerRef.current = new IntersectionObserver(pageObserverCallback, {
189
+ root: null,
190
+ rootMargin: '500px',
191
+ threshold: 0.01
192
+ });
193
+ return () => {
194
+ // Cleanup: disconnette l'observer quando il componente viene smontato
195
+ observerRef.current?.disconnect();
196
+ };
197
+ }, [pageObserverCallback]);
198
+ const showMatchDetails = () => {
199
+ const highlightMatch = (context, matchText) => {
200
+ const matchIndex = context.indexOf(matchText);
201
+ if (matchIndex === -1) {
202
+ // Se non trova il match esatto, prova con una versione normalizzata
203
+ const normalizedContext = context.replace(/\s+/g, ' ');
204
+ const normalizedMatch = matchText.replace(/\s+/g, ' ');
205
+ const normalizedIndex = normalizedContext.indexOf(normalizedMatch);
206
+ if (normalizedIndex === -1) {
207
+ // Se ancora non trova, mostra tutto in grassetto rosso
208
+ return _jsx("strong", { style: { color: '#d32f2f', fontWeight: 'bold' }, children: context });
209
+ }
210
+ return (_jsxs(_Fragment, { children: [normalizedContext.substring(0, normalizedIndex), _jsx("strong", { style: { color: '#d32f2f', fontWeight: 'bold', background: '#ffebee' }, children: normalizedContext.substring(normalizedIndex, normalizedIndex + normalizedMatch.length) }), normalizedContext.substring(normalizedIndex + normalizedMatch.length)] }));
211
+ }
212
+ return (_jsxs(_Fragment, { children: [context.substring(0, matchIndex), _jsx("strong", { style: { color: '#d32f2f', fontWeight: 'bold', background: '#ffebee' }, children: context.substring(matchIndex, matchIndex + matchText.length) }), context.substring(matchIndex + matchText.length)] }));
213
+ };
214
+ TMMessageBoxManager.show({
215
+ title: `${SDKUI_Localizator.Attention}: ${SDKUI_Localizator.PotentiallyUnsafeContent}`,
216
+ buttons: [ButtonNames.OK],
217
+ showToppy: false,
218
+ resizable: true,
219
+ initialWidth: !isMobile ? '800px' : undefined,
220
+ message: (_jsxs("div", { style: { maxHeight: '500px', overflowY: 'auto', padding: '10px', lineHeight: '1.6' }, children: [_jsxs("div", { style: {
221
+ marginBottom: '20px',
222
+ padding: '12px',
223
+ background: '#fff3cd',
224
+ border: '1px solid #ffc107',
225
+ borderRadius: '6px',
226
+ fontSize: '14px',
227
+ wordBreak: 'normal',
228
+ hyphens: 'none'
229
+ }, children: [_jsxs("strong", { children: [SDKUI_Localizator.Attention, ":"] }), " ", SDKUI_Localizator.PotentiallyUnsafeCodePatternsDetected.replaceParams(jsMatches.length.toString())] }), jsMatches.length > 0 ? (jsMatches.map((match, index) => (_jsxs("div", { style: {
230
+ marginBottom: '16px',
231
+ padding: '16px',
232
+ border: '1px solid #ffcdd2',
233
+ borderRadius: '8px',
234
+ background: '#fff',
235
+ boxShadow: '0 1px 3px rgba(0,0,0,0.1)'
236
+ }, children: [_jsx("div", { style: {
237
+ marginBottom: '12px',
238
+ paddingBottom: '8px',
239
+ borderBottom: '2px solid #f44336'
240
+ }, children: _jsxs("strong", { style: {
241
+ color: '#d32f2f',
242
+ fontSize: '15px',
243
+ display: 'flex',
244
+ alignItems: 'center',
245
+ gap: '8px'
246
+ }, children: [_jsx("span", { style: {
247
+ background: '#f44336',
248
+ color: '#fff',
249
+ borderRadius: '50%',
250
+ width: '24px',
251
+ height: '24px',
252
+ display: 'inline-flex',
253
+ alignItems: 'center',
254
+ justifyContent: 'center',
255
+ fontSize: '13px',
256
+ fontWeight: 'bold'
257
+ }, children: index + 1 }), match.name] }) }), _jsx("div", { style: { fontSize: '13px' }, children: _jsx("div", { style: {
258
+ background: '#f5f5f5',
259
+ padding: '10px',
260
+ borderRadius: '4px',
261
+ borderLeft: '3px solid #f44336',
262
+ fontFamily: 'Consolas, Monaco, monospace',
263
+ fontSize: '12px',
264
+ wordBreak: 'break-all',
265
+ color: '#333',
266
+ maxHeight: '200px',
267
+ overflowY: 'auto',
268
+ userSelect: 'text'
269
+ }, children: highlightMatch(match.context, match.match) }) })] }, index)))) : (_jsx("div", { style: { textAlign: 'center', padding: '20px', color: '#999' }, children: "Nessun dettaglio disponibile" }))] }))
270
+ });
271
+ };
272
+ // Mostra loading durante la validazione
273
+ if (isCheckingPdf) {
274
+ return (_jsx(PDFViewerContainer, { children: _jsxs("div", { style: {
275
+ display: 'flex',
276
+ justifyContent: 'center',
277
+ alignItems: 'center',
278
+ height: '100%',
279
+ flexDirection: 'column',
280
+ gap: '10px'
281
+ }, children: [_jsx(LoadIndicator, { height: 60, width: 60 }), _jsx("div", { children: "Validazione PDF in corso..." })] }) }));
282
+ }
283
+ /**
284
+ * Usa <iframe> nei seguenti casi:
285
+ * 1. react-pdf non è disponibile (libreria non installata)
286
+ * 2. Desktop E nessun contenuto JavaScript rilevato (visualizzazione nativa del browser più performante)
287
+ *
288
+ * L'iframe sfrutta il visualizzatore PDF nativo del browser, ma non può prevenire
289
+ * l'esecuzione di JavaScript embedded nel PDF.
290
+ */
291
+ if (!isReactPdfAvailable || (!isMobile && !hasUnsafeContent && pdfUrl)) {
292
+ return (_jsx(PDFViewerContainer, { children: _jsx("iframe", { src: `${pdfUrl}#${enableFitToWidth ? 'view=FitH&' : ''}scrollbar=1`, title: title, style: {
293
+ width: '100%',
294
+ height: '100%',
295
+ border: 'none',
296
+ zIndex: 0,
297
+ pointerEvents: isResizingActive === true ? "none" : "auto"
298
+ } }, pdfUrl) }));
299
+ }
300
+ /**
301
+ * Usa react-pdf nei seguenti casi:
302
+ * 1. Dispositivo mobile (migliore esperienza utente con lazy loading)
303
+ * 2. Desktop con contenuto JavaScript rilevato (rendering sicuro senza esecuzione di script)
304
+ *
305
+ * react-pdf renderizza il PDF come canvas, prevenendo l'esecuzione di JavaScript embedded,
306
+ * ma è meno performante dell'iframe nativo su desktop.
307
+ */
308
+ return _jsxs(PDFViewerContainer, { style: { display: 'flex', flexDirection: 'column' }, children: [loadedPagesNumber === 0 && totalPagesNumber > 0 && _jsx(LoadingOverlay, { children: _jsxs("div", { style: {
309
+ display: 'flex',
310
+ justifyContent: 'center',
311
+ alignItems: 'center',
312
+ flexDirection: 'column',
313
+ gap: '10px'
314
+ }, children: [_jsx(LoadIndicator, { height: 60, width: 60 }), _jsxs("div", { children: [SDKUI_Localizator.Loading, "..."] })] }) }), _jsx("div", { style: {
315
+ display: loadedPagesNumber > 0 && totalPagesNumber > 0 ? 'block' : 'none',
316
+ flex: 1,
317
+ overflow: 'auto'
318
+ }, children: _jsx(Document, { file: pdfBlob, onLoadSuccess: ({ numPages }) => {
319
+ setTotalPagesNumber(numPages);
320
+ setLoadedPagesNumber(0);
321
+ }, loading: _jsxs("div", { style: {
322
+ display: 'flex',
323
+ justifyContent: 'center',
324
+ alignItems: 'center',
325
+ height: '100%',
326
+ flexDirection: 'column',
327
+ gap: '10px'
328
+ }, children: [_jsx(LoadIndicator, { height: 60, width: 60 }), _jsxs("div", { children: [SDKUI_Localizator.Loading, "..."] })] }), error: _jsxs("div", { style: {
329
+ display: 'flex',
330
+ justifyContent: 'center',
331
+ alignItems: 'center',
332
+ height: '100%',
333
+ flexDirection: 'column',
334
+ gap: '10px'
335
+ }, children: [_jsx(IconCloseOutline, { fontSize: 64, color: TMColors.error }), _jsx("div", { children: "Errore nel caricamento del PDF" })] }), children: Array.from(new Array(totalPagesNumber), (el, index) => {
336
+ const pageNumber = index + 1;
337
+ const shouldRender = visiblePages.has(pageNumber);
338
+ return (_jsx("div", { "data-page-number": pageNumber, ref: (el) => {
339
+ if (el && observerRef.current) {
340
+ observerRef.current.observe(el);
341
+ }
342
+ }, style: {
343
+ minHeight: shouldRender ? 'auto' : '1000px',
344
+ display: 'flex',
345
+ justifyContent: 'center',
346
+ alignItems: 'center'
347
+ }, children: shouldRender && (_jsx(Page, { pageNumber: pageNumber, renderTextLayer: false, renderAnnotationLayer: false, width: Math.min(window.innerWidth - 40, 1200), loading: _jsx("div", { style: { padding: '20px' }, children: _jsx(LoadIndicator, { height: 40, width: 40 }) }), onLoadSuccess: () => {
348
+ setLoadedPagesNumber(prev => prev + 1);
349
+ } })) }, `page_${pageNumber}`));
350
+ }) }) }), hasUnsafeContent && (_jsxs("div", { style: {
351
+ display: 'flex',
352
+ justifyContent: 'center',
353
+ alignItems: 'center',
354
+ padding: '12px 20px',
355
+ background: '#fff3cd',
356
+ borderTop: '2px solid #ffc107',
357
+ gap: '8px',
358
+ flexShrink: 0
359
+ }, children: [_jsxs("span", { style: {
360
+ color: '#856404',
361
+ whiteSpace: 'nowrap',
362
+ overflow: 'hidden',
363
+ textOverflow: 'ellipsis',
364
+ flex: 1
365
+ }, children: [_jsx("strong", { children: "Attenzione:" }), " Questo documento contiene contenuti potenzialmente non sicuri."] }), jsMatches.length > 0 && (_jsx("span", { className: "dx-icon-info", style: {
366
+ fontSize: '20px',
367
+ color: '#d32f2f',
368
+ cursor: 'pointer',
369
+ transition: 'color 0.2s',
370
+ marginLeft: '4px'
371
+ }, onClick: showMatchDetails, title: "Clicca per vedere i dettagli", onMouseEnter: (e) => e.currentTarget.style.color = '#b71c1c', onMouseLeave: (e) => e.currentTarget.style.color = '#d32f2f' }))] }))] });
372
+ };
373
+ export default TMPdfViewer;
@@ -19,6 +19,8 @@ const StyledToppyText = styled.div `
19
19
  color: #2559A5;
20
20
  font-size: 1rem;
21
21
  user-select: none;
22
+ -webkit-touch-callout: none;
23
+ -webkit-user-select: none;
22
24
  margin: 0;
23
25
  display: -webkit-box;
24
26
  -webkit-box-orient: vertical;
@@ -35,6 +37,8 @@ const StyledToppyImage = styled.img `
35
37
  height: auto;
36
38
  display: block;
37
39
  user-select: none;
40
+ -webkit-touch-callout: none;
41
+ -webkit-user-select: none;
38
42
  `;
39
43
  const TMToppyMessage = (props) => {
40
44
  const { message, titleTooltip, maxWidth } = props;
@@ -1,11 +1,20 @@
1
1
  import React from "react";
2
- import { DcmtTypeDescriptor, FileDescriptor, UserDescriptor } from "@topconsultnpm/sdk-ts";
2
+ import { AccessLevels, DcmtTypeDescriptor, FileDescriptor, UserDescriptor } from "@topconsultnpm/sdk-ts";
3
3
  import { DcmtInfo, DownloadModes, DownloadTypes } from "../ts/types";
4
4
  import { FileItem } from "../components";
5
5
  /**
6
6
  * Check-in/Check-out Manager
7
7
  * Questo modulo gestisce tutte le operazioni di check-in e check-out
8
8
  * dei documenti e delle bozze dei gruppi di lavoro.
9
+ *
10
+ * Operazioni gestite:
11
+ * - Generazione nomi file per download e checkout con timestamp e identificatori univoci
12
+ * - Download di documenti in modalità checkout
13
+ * - Gestione dello storage locale delle informazioni di checkout (aggiunta, aggiornamento, rimozione)
14
+ * - Validazione dei nomi file secondo le convenzioni di naming CICO
15
+ * - Rendering dell'interfaccia utente per conferma check-in con visualizzazione anomalie
16
+ * - Determinazione dello stato di check-out dei documenti (editMode/lockMode)
17
+ * - Verifica permessi e abilitazione funzionalità CICO per tipo documento
9
18
  */
10
19
  export interface CheckoutInfo {
11
20
  DID: string;
@@ -18,6 +27,7 @@ interface CheckoutStatusResult {
18
27
  mode: 'editMode' | 'lockMode' | '';
19
28
  version: number;
20
29
  icon: React.ReactNode | null;
30
+ editLockTooltipText: React.ReactNode | null;
21
31
  }
22
32
  export type DownloadSource = {
23
33
  type: 'fileItem';
@@ -48,6 +58,26 @@ type FileNameValidation = {
48
58
  validationResults?: FileNameValidationItems;
49
59
  };
50
60
  export declare const renderCicoCheckInContent: (source: DownloadSource, selectedFilename: File, isValid: boolean, validationItems: FileNameValidationItems | undefined, color?: string) => React.ReactNode;
61
+ interface CheckInCheckOutDcmtInfo {
62
+ CICO: number;
63
+ CanCICO: AccessLevels;
64
+ CanDelChronology: AccessLevels;
65
+ UserID_MID: number;
66
+ Date_MID: number;
67
+ Ver_MID: number;
68
+ UserID_CanViewOrUpdate: AccessLevels;
69
+ Date_CanViewOrUpdate: AccessLevels;
70
+ Ver_CanViewOrUpdate: AccessLevels;
71
+ }
72
+ export declare const getDcmtCicoInfo: (dtd: DcmtTypeDescriptor | undefined) => CheckInCheckOutDcmtInfo;
73
+ /**
74
+ * Determina lo stato di check-in/check-out di un documento
75
+ *
76
+ * @param dcmt - Il documento in formato array (MetadataValueDescriptorEx[]) o oggetto piatto
77
+ * @param allUsers - Lista di tutti gli utenti per risolvere i nomi
78
+ * @param dtd - Descrittore del tipo documento contenente le definizioni dei metadati CICO
79
+ * @returns Oggetto con cicoEnabled (se CICO è abilitato) e checkoutStatus (dettagli dello stato)
80
+ */
51
81
  export declare const getDcmtCicoStatus: (dcmt: any, allUsers: Array<UserDescriptor>, dtd: DcmtTypeDescriptor | undefined) => {
52
82
  cicoEnabled: boolean;
53
83
  checkoutStatus: CheckoutStatusResult;
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { AccessLevels, CICO_MetadataNames, SDK_Globals } from "@topconsultnpm/sdk-ts";
2
+ import { AccessLevels, CICO_MetadataNames, SDK_Globals, SystemMIDsAsNumber } from "@topconsultnpm/sdk-ts";
3
3
  import TMTooltip from "../components/base/TMTooltip";
4
4
  import { Globalization, SDKUI_Globals, SDKUI_Localizator } from "./index";
5
5
  import { DownloadTypes } from "../ts/types";
@@ -191,7 +191,7 @@ export const renderCicoCheckInContent = (source, selectedFilename, isValid, vali
191
191
  const fileName = source.type === 'fileItem' ? source.fileItem.name : (source.dcmtInfo.fileName ?? SDKUI_Localizator.SearchResult);
192
192
  return _jsxs("div", { style: { width: "100%", height: "100%" }, children: [SDKUI_Localizator.CheckInElementConfirm.replaceParams(fileName), !isValid && _jsxs("div", { style: { width: "100%", height: "100%", marginTop: '15px' }, children: [_jsxs("div", { style: { display: 'flex', flexDirection: 'column' }, children: [_jsx("div", { style: { fontSize: '12px', color, marginBottom: '12px' }, children: SDKUI_Localizator.ElementNameConventionError }), _jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: '6px' }, children: [_jsxs("div", { style: { color }, children: [_jsx("strong", { style: { color }, children: SDKUI_Localizator.Expected }), ":", ' ', _jsx("span", { style: { fontStyle: 'italic' }, children: getCicoDownloadFileName(source, true, false) })] }), _jsxs("div", { style: { color }, children: [_jsx("strong", { style: { color }, children: SDKUI_Localizator.SelectedSingular }), ":", ' ', _jsx("span", { style: { fontStyle: 'italic' }, children: selectedFilename.name })] })] })] }), validationItems && Object.entries(validationItems).filter(([_, value]) => !value.isValid).length > 0 && (_jsxs("div", { style: { width: "100%", height: "100%", marginTop: '15px' }, children: [_jsx("hr", {}), _jsxs("table", { style: { width: "100%", borderCollapse: "collapse", color }, children: [_jsx("caption", { style: { textAlign: "center", fontWeight: "bold", marginBottom: "5px" }, children: SDKUI_Localizator.Anomalies }), _jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { style: { textAlign: "left", borderBottom: "1px solid #eee" }, children: SDKUI_Localizator.Value }), _jsx("th", { style: { textAlign: "left", borderBottom: "1px solid #eee" }, children: SDKUI_Localizator.Expected }), _jsx("th", { style: { textAlign: "left", borderBottom: "1px solid #eee" }, children: SDKUI_Localizator.Current })] }) }), _jsx("tbody", { children: Object.entries(validationItems).filter(([_, value]) => !value.isValid).map(([key, result]) => (_jsxs("tr", { children: [_jsx("td", { style: { borderBottom: "1px solid #eee" }, children: _jsx("strong", { style: { textTransform: "capitalize" }, children: key }) }), _jsxs("td", { style: { borderBottom: "1px solid #eee" }, children: [" ", result.expected || "-"] }), _jsxs("td", { style: { borderBottom: "1px solid #eee" }, children: [" ", result.current || "-"] })] }, key))) })] }), _jsx("hr", {})] })), _jsx("div", { style: { fontSize: '12px', marginTop: '15px', marginBottom: '15px' }, children: SDKUI_Localizator.ProceedAnyway })] })] });
193
193
  };
194
- const getDcmtCicoInfo = (dtd) => {
194
+ export const getDcmtCicoInfo = (dtd) => {
195
195
  const cico = {
196
196
  CICO: 0,
197
197
  CanCICO: AccessLevels.No,
@@ -210,57 +210,139 @@ const getDcmtCicoInfo = (dtd) => {
210
210
  cico.CanDelChronology = dtd.perm?.canDelChron ?? AccessLevels.No;
211
211
  const mdCheckout = dtd.metadata?.find(md => md.name === CICO_MetadataNames.CICO_CheckoutUserID);
212
212
  if (mdCheckout) {
213
- cico.UserID_MID = mdCheckout.fromMID;
213
+ cico.UserID_MID = mdCheckout.id;
214
214
  cico.UserID_CanViewOrUpdate = (mdCheckout.perm?.canView == AccessLevels.Yes || mdCheckout.perm?.canUpdate == AccessLevels.Yes) ? AccessLevels.Yes : AccessLevels.No;
215
215
  }
216
216
  const mdDate = dtd.metadata?.find(md => md.name === CICO_MetadataNames.CICO_CheckoutDate);
217
217
  if (mdDate) {
218
- cico.Date_MID = mdDate.fromMID;
218
+ cico.Date_MID = mdDate.id;
219
219
  cico.Date_CanViewOrUpdate = (mdDate.perm?.canView == AccessLevels.Yes || mdDate.perm?.canUpdate == AccessLevels.Yes) ? AccessLevels.Yes : AccessLevels.No;
220
220
  }
221
221
  const mdVer = dtd.metadata?.find(md => md.name === CICO_MetadataNames.CICO_Version);
222
222
  if (mdVer) {
223
- cico.Ver_MID = mdVer.fromMID;
223
+ cico.Ver_MID = mdVer.id;
224
224
  cico.Ver_CanViewOrUpdate = (mdVer.perm?.canView == AccessLevels.Yes || mdVer.perm?.canUpdate == AccessLevels.Yes) ? AccessLevels.Yes : AccessLevels.No;
225
225
  }
226
226
  return cico;
227
227
  };
228
+ /**
229
+ * Determina lo stato di check-in/check-out di un documento
230
+ *
231
+ * @param dcmt - Il documento in formato array (MetadataValueDescriptorEx[]) o oggetto piatto
232
+ * @param allUsers - Lista di tutti gli utenti per risolvere i nomi
233
+ * @param dtd - Descrittore del tipo documento contenente le definizioni dei metadati CICO
234
+ * @returns Oggetto con cicoEnabled (se CICO è abilitato) e checkoutStatus (dettagli dello stato)
235
+ */
228
236
  export const getDcmtCicoStatus = (dcmt, allUsers, dtd) => {
237
+ // ========================================================================
238
+ // VALIDAZIONE PARAMETRI
239
+ // ========================================================================
240
+ // Se i parametri essenziali non sono forniti, ritorna stato di default
229
241
  if (dcmt === undefined || dtd === undefined) {
230
242
  return {
231
243
  cicoEnabled: false,
232
- checkoutStatus: { isCheckedOut: false, mode: '', version: 1, icon: null }
244
+ checkoutStatus: { isCheckedOut: false, mode: '', version: 1, icon: null, editLockTooltipText: null }
233
245
  };
234
246
  }
247
+ // ========================================================================
248
+ // ESTRAZIONE INFORMAZIONI CICO DAL DTD
249
+ // ========================================================================
250
+ // Recupera le configurazioni e permessi CICO dal tipo documento
235
251
  const cicoInfo = getDcmtCicoInfo(dtd);
236
- const CICO_CheckoutUserID_Meta = dtd?.metadata?.find(md => md.name === CICO_MetadataNames.CICO_CheckoutUserID);
237
- const CICO_CheckoutDate_Meta = dtd?.metadata?.find(md => md.name === CICO_MetadataNames.CICO_CheckoutDate);
238
- const CICO_Version_Meta = dtd?.metadata?.find(md => md.name === CICO_MetadataNames.CICO_Version);
239
- const keyVersion = dcmt.TID + "_" + (CICO_Version_Meta?.id ?? 0);
240
- const versionRaw = CICO_Version_Meta?.id ? dcmt[keyVersion] : undefined;
241
- const version = (versionRaw != null && !isNaN(Number(versionRaw))) ? Number(versionRaw) : 1;
242
- let checkoutStatus = { isCheckedOut: false, mode: '', version: version, icon: null, };
243
252
  const userID = SDK_Globals.tmSession?.SessionDescr?.userID;
244
- if (dcmt && CICO_CheckoutUserID_Meta?.id) {
245
- const keyUserID = dcmt.TID + "_" + CICO_CheckoutUserID_Meta.id;
246
- const checkoutUserIdValue = dcmt[keyUserID];
247
- const checkoutUserId = Number(checkoutUserIdValue);
248
- if (userID && checkoutUserIdValue && !isNaN(checkoutUserId) && checkoutUserId > 0) {
249
- // editMode: l'utente corrente è quello che ha fatto il checkout
250
- // lockMode: un altro utente ha fatto il checkout
251
- const mode = (userID && userID === checkoutUserId) ? 'editMode' : 'lockMode';
252
- // Recupera i dati aggiuntivi per il tooltip
253
- const keyDate = dcmt.TID + "_" + (CICO_CheckoutDate_Meta?.id ?? 0);
254
- const checkoutDate = CICO_CheckoutDate_Meta?.id ? dcmt[keyDate] : undefined;
255
- const editLockTooltipText = _jsxs(_Fragment, { children: [_jsxs("div", { style: { textAlign: "center" }, children: [mode === 'editMode' && (_jsxs(_Fragment, { children: [_jsx("i", { style: { fontSize: "18px", color: colors.MEDIUM_GREEN, fontWeight: "bold" }, className: "dx-icon-edit" }), SDKUI_Localizator.CurrentUserExtract] })), mode === '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(allUsers, checkoutUserId), " (ID: ", checkoutUserId, ")"] }), _jsxs("li", { children: ["- ", _jsx("span", { style: { fontWeight: 'bold' }, children: SDKUI_Localizator.ExtractedOn }), ": ", Globalization.getDateTimeDisplayValue(checkoutDate?.toString())] })] }), _jsx("hr", {}), _jsx("ul", { children: _jsxs("li", { children: ["- ", _jsx("span", { style: { fontWeight: 'bold' }, children: SDKUI_Localizator.Version }), ": ", version ?? 1] }) })] })] });
256
- const icon = mode === 'editMode'
257
- ? _jsx(TMTooltip, { content: editLockTooltipText, children: _jsx("i", { style: { fontSize: "18px", color: colors.MEDIUM_GREEN, fontWeight: "bold" }, className: "dx-icon-edit" }) })
258
- : _jsx(TMTooltip, { content: editLockTooltipText, children: _jsx("i", { style: { fontSize: "18px", color: colors.MEDIUM_GREEN, fontWeight: "bold" }, className: "dx-icon-lock" }) });
259
- checkoutStatus = { isCheckedOut: true, mode: mode, icon: icon, version: version };
253
+ // Variabili comuni per entrambi i formati di documento
254
+ let checkoutUserId;
255
+ let checkoutDate;
256
+ let version = 1;
257
+ let fileExt;
258
+ // ========================================================================
259
+ // CASO 1: Documento come Array di MetadataValueDescriptorEx
260
+ // ========================================================================
261
+ // Questo formato viene utilizzato quando il documento proviene da query
262
+ // o liste dove ogni metadato è un oggetto separato con proprietà 'md' e 'value'
263
+ if (Array.isArray(dcmt) && dcmt.length > 0 && dcmt[0]?.md !== undefined) {
264
+ const dcmtsArray = dcmt;
265
+ // Estrai l'ID dell'utente che ha effettuato il checkout
266
+ const checkoutUserIdProperty = dcmtsArray.find((item) => item.md?.name === CICO_MetadataNames.CICO_CheckoutUserID);
267
+ const checkoutUserIdValue = checkoutUserIdProperty?.value;
268
+ checkoutUserId = checkoutUserIdValue ? Number(checkoutUserIdValue) : undefined;
269
+ // Estrai la data di checkout
270
+ const checkoutDateProperty = dcmtsArray.find((item) => item.md?.name === CICO_MetadataNames.CICO_CheckoutDate);
271
+ checkoutDate = checkoutDateProperty?.value;
272
+ // Estrai la versione del documento
273
+ const versionProperty = dcmtsArray.find((item) => item.md?.name === CICO_MetadataNames.CICO_Version);
274
+ const versionRaw = versionProperty?.value;
275
+ version = (versionRaw != null && !isNaN(Number(versionRaw))) ? Number(versionRaw) : 1;
276
+ const fileExtProperty = dcmtsArray.find((item) => item.mid === SystemMIDsAsNumber.FileExt);
277
+ fileExt = fileExtProperty?.value ? fileExtProperty.value.toString() : null;
278
+ }
279
+ // ========================================================================
280
+ // CASO 2: Documento come Oggetto Piatto (formato standard)
281
+ // ========================================================================
282
+ // Questo formato viene utilizzato quando il documento ha proprietà dirette
283
+ // nel formato chiave-valore: TID, DID, e "TID_MetadataID" per i metadati
284
+ else {
285
+ // Trova i metadati CICO nel descrittore del tipo documento
286
+ const CICO_CheckoutUserID_Meta = dtd.metadata?.find(md => md.name === CICO_MetadataNames.CICO_CheckoutUserID);
287
+ const CICO_CheckoutDate_Meta = dtd.metadata?.find(md => md.name === CICO_MetadataNames.CICO_CheckoutDate);
288
+ const CICO_Version_Meta = dtd.metadata?.find(md => md.name === CICO_MetadataNames.CICO_Version);
289
+ fileExt = dcmt.FILEEXT ? dcmt.FILEEXT.toString() : null;
290
+ // Estrai l'ID dell'utente che ha effettuato il checkout
291
+ if (CICO_CheckoutUserID_Meta?.id) {
292
+ const keyUserID = dcmt.TID + "_" + CICO_CheckoutUserID_Meta.id;
293
+ const checkoutUserIdValue = dcmt[keyUserID];
294
+ checkoutUserId = checkoutUserIdValue ? Number(checkoutUserIdValue) : undefined;
295
+ }
296
+ // Estrai la data di checkout
297
+ if (CICO_CheckoutDate_Meta?.id) {
298
+ const keyDate = dcmt.TID + "_" + CICO_CheckoutDate_Meta.id;
299
+ checkoutDate = dcmt[keyDate];
300
+ }
301
+ // Estrai la versione del documento
302
+ if (CICO_Version_Meta?.id) {
303
+ const keyVersion = dcmt.TID + "_" + CICO_Version_Meta.id;
304
+ const versionRaw = dcmt[keyVersion];
305
+ version = (versionRaw != null && !isNaN(Number(versionRaw))) ? Number(versionRaw) : 1;
260
306
  }
261
307
  }
308
+ // ========================================================================
309
+ // COSTRUZIONE DELLO STATO DI CHECKOUT
310
+ // ========================================================================
311
+ let checkoutStatus = {
312
+ isCheckedOut: false,
313
+ mode: '',
314
+ version: version,
315
+ icon: null,
316
+ editLockTooltipText: null
317
+ };
318
+ // Verifica se il documento è effettivamente in stato di checkout
319
+ if (userID && checkoutUserId && !isNaN(checkoutUserId) && checkoutUserId > 0) {
320
+ // Determina la modalità in base all'utente:
321
+ // - editMode: l'utente corrente può modificare (è lui che ha fatto il checkout)
322
+ // - lockMode: il documento è bloccato da un altro utente
323
+ const mode = (userID === checkoutUserId) ? 'editMode' : 'lockMode';
324
+ // ====================================================================
325
+ // COSTRUZIONE DEL TOOLTIP INFORMATIVO
326
+ // ====================================================================
327
+ const editLockTooltipText = (_jsxs(_Fragment, { children: [_jsxs("div", { style: { textAlign: "center" }, children: [mode === 'editMode' && (_jsxs(_Fragment, { children: [_jsx("i", { style: { fontSize: "18px", color: colors.MEDIUM_GREEN, fontWeight: "bold" }, className: "dx-icon-edit" }), SDKUI_Localizator.CurrentUserExtract] })), mode === '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(allUsers, checkoutUserId), " (ID: ", checkoutUserId, ")"] }), _jsxs("li", { children: ["- ", _jsx("span", { style: { fontWeight: 'bold' }, children: SDKUI_Localizator.ExtractedOn }), ": ", Globalization.getDateTimeDisplayValue(checkoutDate?.toString())] })] }), _jsx("hr", {}), _jsx("ul", { children: _jsxs("li", { children: ["- ", _jsx("span", { style: { fontWeight: 'bold' }, children: SDKUI_Localizator.Version }), ": ", version] }) })] })] }));
328
+ // Crea l'icona con tooltip appropriata alla modalità
329
+ const icon = mode === 'editMode'
330
+ ? _jsx(TMTooltip, { content: editLockTooltipText, children: _jsx("i", { style: { fontSize: "18px", color: colors.MEDIUM_GREEN, fontWeight: "bold" }, className: "dx-icon-edit" }) })
331
+ : _jsx(TMTooltip, { content: editLockTooltipText, children: _jsx("i", { style: { fontSize: "18px", color: colors.MEDIUM_GREEN, fontWeight: "bold" }, className: "dx-icon-lock" }) });
332
+ checkoutStatus = {
333
+ isCheckedOut: true,
334
+ mode: mode,
335
+ icon: icon,
336
+ version: version,
337
+ editLockTooltipText: editLockTooltipText
338
+ };
339
+ }
340
+ // ========================================================================
341
+ // RESTITUZIONE RISULTATO FINALE
342
+ // ========================================================================
262
343
  return {
263
- cicoEnabled: cicoInfo.CICO === 1 && cicoInfo.CanCICO === AccessLevels.Yes,
344
+ // CICO è abilitato se configurato nel DTD e l'utente ha i permessi
345
+ cicoEnabled: cicoInfo.CICO === 1 && cicoInfo.CanCICO === AccessLevels.Yes && fileExt !== null && fileExt !== '',
264
346
  checkoutStatus: checkoutStatus
265
347
  };
266
348
  };