@topconsultnpm/sdkui-react 6.20.0-dev1.7 → 6.20.0-dev1.70

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 (116) hide show
  1. package/lib/components/NewComponents/ContextMenu/TMContextMenu.js +258 -17
  2. package/lib/components/NewComponents/ContextMenu/hooks.d.ts +2 -0
  3. package/lib/components/NewComponents/ContextMenu/hooks.js +17 -4
  4. package/lib/components/NewComponents/ContextMenu/index.d.ts +3 -0
  5. package/lib/components/NewComponents/ContextMenu/index.js +2 -0
  6. package/lib/components/NewComponents/ContextMenu/styles.d.ts +5 -1
  7. package/lib/components/NewComponents/ContextMenu/styles.js +59 -31
  8. package/lib/components/NewComponents/ContextMenu/types.d.ts +13 -0
  9. package/lib/components/NewComponents/ContextMenu/useLongPress.d.ts +21 -0
  10. package/lib/components/NewComponents/ContextMenu/useLongPress.js +112 -0
  11. package/lib/components/NewComponents/FloatingMenuBar/TMFloatingMenuBar.js +517 -100
  12. package/lib/components/NewComponents/FloatingMenuBar/styles.d.ts +19 -5
  13. package/lib/components/NewComponents/FloatingMenuBar/styles.js +206 -54
  14. package/lib/components/NewComponents/FloatingMenuBar/types.d.ts +1 -2
  15. package/lib/components/base/TMAccordionNew.js +35 -14
  16. package/lib/components/base/TMCustomButton.js +61 -17
  17. package/lib/components/base/TMDataGrid.d.ts +7 -4
  18. package/lib/components/base/TMDataGrid.js +142 -11
  19. package/lib/components/base/TMDropDownMenu.js +19 -18
  20. package/lib/components/base/TMPanel.js +1 -1
  21. package/lib/components/choosers/TMInvoiceRetrieveFormats.js +1 -1
  22. package/lib/components/choosers/TMMetadataChooser.js +8 -1
  23. package/lib/components/choosers/TMOrderRetrieveFormats.js +1 -1
  24. package/lib/components/choosers/TMUserChooser.d.ts +0 -5
  25. package/lib/components/choosers/TMUserChooser.js +25 -45
  26. package/lib/components/editors/TMMetadataValues.js +23 -5
  27. package/lib/components/editors/TMTextBox.js +6 -3
  28. package/lib/components/features/documents/TMDcmtForm.d.ts +13 -1
  29. package/lib/components/features/documents/TMDcmtForm.js +386 -194
  30. package/lib/components/features/documents/TMDcmtPreview.js +41 -105
  31. package/lib/components/features/documents/TMMasterDetailDcmts.js +37 -52
  32. package/lib/components/features/documents/TMRelationViewer.d.ts +1 -1
  33. package/lib/components/features/documents/TMRelationViewer.js +2 -2
  34. package/lib/components/features/search/TMDcmtCheckoutInfoForm.d.ts +8 -0
  35. package/lib/components/features/search/{TMSearchResultCheckoutInfoForm.js → TMDcmtCheckoutInfoForm.js} +5 -10
  36. package/lib/components/features/search/TMSavedQuerySelector.js +72 -67
  37. package/lib/components/features/search/TMSearch.js +41 -9
  38. package/lib/components/features/search/TMSearchQueryPanel.d.ts +1 -0
  39. package/lib/components/features/search/TMSearchQueryPanel.js +19 -18
  40. package/lib/components/features/search/TMSearchResult.js +118 -242
  41. package/lib/components/features/search/TMSearchResultsMenuItems.d.ts +3 -3
  42. package/lib/components/features/search/TMSearchResultsMenuItems.js +205 -169
  43. package/lib/components/features/search/TMSignSettingsForm.js +1 -1
  44. package/lib/components/features/search/TMSignatureInfoContent.d.ts +6 -0
  45. package/lib/components/features/search/TMSignatureInfoContent.js +140 -0
  46. package/lib/components/features/search/TMViewHistoryDcmt.js +1 -1
  47. package/lib/components/features/tasks/TMTaskForm.js +20 -1
  48. package/lib/components/features/tasks/TMTasksUtils.d.ts +2 -2
  49. package/lib/components/features/tasks/TMTasksUtils.js +62 -52
  50. package/lib/components/features/tasks/TMTasksView.js +6 -6
  51. package/lib/components/features/workflow/TMWorkflowPopup.d.ts +33 -2
  52. package/lib/components/features/workflow/TMWorkflowPopup.js +134 -24
  53. package/lib/components/features/workflow/diagram/DiagramItemComponent.d.ts +1 -0
  54. package/lib/components/features/workflow/diagram/DiagramItemComponent.js +2 -3
  55. package/lib/components/features/workflow/diagram/RecipientList.js +3 -2
  56. package/lib/components/features/workflow/diagram/WFDiagram.d.ts +2 -0
  57. package/lib/components/features/workflow/diagram/WFDiagram.js +21 -4
  58. package/lib/components/forms/Login/LoginValidatorService.d.ts +2 -0
  59. package/lib/components/forms/Login/LoginValidatorService.js +7 -2
  60. package/lib/components/forms/Login/TMLoginForm.js +34 -6
  61. package/lib/components/forms/TMChooserForm.js +1 -1
  62. package/lib/components/grids/TMBlogsPost.js +55 -30
  63. package/lib/components/grids/TMRecentsManager.js +20 -10
  64. package/lib/components/index.d.ts +4 -0
  65. package/lib/components/index.js +4 -0
  66. package/lib/components/settings/SettingsAppearance.js +92 -29
  67. package/lib/components/viewers/TMDataListItemViewer.d.ts +2 -1
  68. package/lib/components/viewers/TMDataListItemViewer.js +35 -71
  69. package/lib/components/viewers/TMDataUserIdItemViewer.d.ts +8 -0
  70. package/lib/components/viewers/TMDataUserIdItemViewer.js +39 -0
  71. package/lib/css/tm-sdkui.css +1 -1
  72. package/lib/helper/SDKUI_Globals.d.ts +19 -0
  73. package/lib/helper/SDKUI_Globals.js +11 -0
  74. package/lib/helper/SDKUI_Localizator.d.ts +15 -1
  75. package/lib/helper/SDKUI_Localizator.js +147 -1
  76. package/lib/helper/TMIcons.d.ts +2 -0
  77. package/lib/helper/TMIcons.js +6 -0
  78. package/lib/helper/TMPdfViewer.d.ts +8 -0
  79. package/lib/helper/TMPdfViewer.js +373 -0
  80. package/lib/helper/checkinCheckoutManager.d.ts +32 -2
  81. package/lib/helper/checkinCheckoutManager.js +115 -38
  82. package/lib/helper/devextremeCustomMessages.d.ts +30 -0
  83. package/lib/helper/devextremeCustomMessages.js +30 -0
  84. package/lib/helper/helpers.d.ts +2 -1
  85. package/lib/helper/helpers.js +14 -3
  86. package/lib/helper/index.d.ts +1 -0
  87. package/lib/helper/index.js +1 -0
  88. package/lib/helper/queryHelper.d.ts +1 -1
  89. package/lib/helper/queryHelper.js +33 -3
  90. package/lib/hooks/useCheckInOutOperations.d.ts +28 -0
  91. package/lib/hooks/useCheckInOutOperations.js +223 -0
  92. package/lib/hooks/useDataListItem.d.ts +12 -0
  93. package/lib/hooks/useDataListItem.js +131 -0
  94. package/lib/hooks/useDataUserIdItem.d.ts +10 -0
  95. package/lib/hooks/useDataUserIdItem.js +96 -0
  96. package/lib/hooks/useSettingsFeedback.d.ts +11 -0
  97. package/lib/hooks/useSettingsFeedback.js +38 -0
  98. package/lib/hooks/useWorkflowApprove.d.ts +4 -0
  99. package/lib/hooks/useWorkflowApprove.js +14 -1
  100. package/lib/index.d.ts +1 -0
  101. package/lib/index.js +1 -0
  102. package/lib/ts/types.d.ts +58 -1
  103. package/lib/utils/theme.d.ts +1 -1
  104. package/lib/utils/theme.js +1 -1
  105. package/package.json +5 -2
  106. package/lib/components/NewComponents/Notification/Notification.d.ts +0 -4
  107. package/lib/components/NewComponents/Notification/Notification.js +0 -60
  108. package/lib/components/NewComponents/Notification/NotificationContainer.d.ts +0 -8
  109. package/lib/components/NewComponents/Notification/NotificationContainer.js +0 -33
  110. package/lib/components/NewComponents/Notification/index.d.ts +0 -2
  111. package/lib/components/NewComponents/Notification/index.js +0 -2
  112. package/lib/components/NewComponents/Notification/styles.d.ts +0 -21
  113. package/lib/components/NewComponents/Notification/styles.js +0 -180
  114. package/lib/components/NewComponents/Notification/types.d.ts +0 -18
  115. package/lib/components/NewComponents/Notification/types.js +0 -1
  116. package/lib/components/features/search/TMSearchResultCheckoutInfoForm.d.ts +0 -8
@@ -0,0 +1,223 @@
1
+ import { useCallback, useState } from 'react';
2
+ import { cicoDownloadFilesCallback, dcmtsFileCachePreview, getCicoDownloadFileName, getExceptionMessage, removeDcmtsFileCache, renderCicoCheckInContent, SDKUI_Globals, SDKUI_Localizator, updateCicoCheckoutStorageItem, validateCicoFileName } from '../helper';
3
+ import { ButtonNames, ShowAlert, TMMessageBoxManager, TMResultManager } from '../components';
4
+ import { ResultTypes, SDK_Globals } from '@topconsultnpm/sdk-ts';
5
+ let abortController = new AbortController();
6
+ export const useCheckInOutOperations = () => {
7
+ const [showHistory, setShowHistory] = useState(false);
8
+ // State to manage show history selected file
9
+ const [showCheckoutInformationForm, setShowCheckoutInformationForm] = useState(false);
10
+ // Stato per triggerare il refresh della preview dall'esterno
11
+ const [refreshPreviewTrigger, setRefreshPreviewTrigger] = useState(0);
12
+ // State to manage comment form
13
+ const [commentFormState, setCommentFormState] = useState({
14
+ removeAndEditAttachment: true,
15
+ show: false,
16
+ isRequired: false
17
+ });
18
+ // State variable to control the visibility of the wait panel
19
+ const [showCicoWaitPanel, setShowCicoWaitPanel] = useState(false);
20
+ // State variable to store the title of the wait panel
21
+ const [cicoWaitPanelTitle, setCicoWaitPanelTitle] = useState('');
22
+ // State variable to control the visibility of the primary section of the wait panel
23
+ const [showCicoPrimaryProgress, setShowCicoPrimaryProgress] = useState(false);
24
+ // State variable to store the primary text of the wait panel
25
+ const [cicoPrimaryProgressText, setCicoPrimaryProgressText] = useState('');
26
+ // State variable to track the current value of the primary progress indicator in the wait panel
27
+ const [cicoPrimaryProgressValue, setCicoPrimaryProgressValue] = useState(0);
28
+ // State variable to define the maximum value for the primary progress indicator in the wait panel
29
+ const [cicoPrimaryProgressMax, setCicoPrimaryProgressMax] = useState(0);
30
+ const showHistoryCallback = useCallback(() => {
31
+ setShowHistory(true);
32
+ }, []);
33
+ const hideHistoryCallback = useCallback(() => {
34
+ setShowHistory(false);
35
+ }, []);
36
+ const showCheckoutInformationFormCallback = useCallback(() => {
37
+ setShowCheckoutInformationForm(true);
38
+ }, []);
39
+ const hideCheckoutInformationFormCallback = useCallback(() => {
40
+ setShowCheckoutInformationForm(false);
41
+ }, []);
42
+ const triggerPreviewRefresh = useCallback(() => {
43
+ setRefreshPreviewTrigger(prev => prev + 1);
44
+ }, []);
45
+ const hideCommentFormCallback = useCallback(() => {
46
+ setCommentFormState(prev => ({ ...prev, show: false }));
47
+ }, []);
48
+ const copyCheckoutPathToClipboardCallback = (dcmt, filename) => {
49
+ const defaultCheckInOutFolder = SDKUI_Globals.userSettings.defaultCheckInOutFolder ?? "Download";
50
+ const wGSDraftCheckoutItemCurrentItems = [...SDKUI_Globals.userSettings.dcmtCheckoutInfo];
51
+ const existingItem = wGSDraftCheckoutItemCurrentItems.find((item) => item.TID === dcmt.TID.toString() && item.DID === dcmt.DID.toString());
52
+ const folder = existingItem && existingItem.checkoutFolder && existingItem.checkoutFolder !== "" ? existingItem.checkoutFolder : defaultCheckInOutFolder;
53
+ const name = existingItem?.checkoutName ?? getCicoDownloadFileName({ type: 'dcmtInfo', dcmtInfo: dcmt, originalFileName: filename }, true, false);
54
+ const textToCopy = folder ? `${folder}\\${name}` : name;
55
+ navigator.clipboard.writeText(textToCopy)
56
+ .then(() => {
57
+ ShowAlert({ message: SDKUI_Localizator.OperationSuccess, mode: 'success', duration: 5000, title: SDKUI_Localizator.CopyToClipboard });
58
+ })
59
+ .catch(err => {
60
+ ShowAlert({ message: err, mode: 'error', duration: 5000, title: SDKUI_Localizator.OperationResult });
61
+ });
62
+ };
63
+ const handleCheckOutCallback = async (dcmt, checkout, filename, downloadDcmtsAsync, refreshMetadataAsync, refreshFocusedDataRowAsync) => {
64
+ if (!dcmt)
65
+ throw new Error("Document info is required");
66
+ const title = checkout ? 'Check out' : SDKUI_Localizator.CancelCheckOut;
67
+ const msg = checkout ? SDKUI_Localizator.ExecuteCheckOutQuestion : SDKUI_Localizator.ExecuteCancelCheckOutQuestion;
68
+ TMMessageBoxManager.show({
69
+ title: title,
70
+ message: msg,
71
+ buttons: [ButtonNames.YES, ButtonNames.NO],
72
+ onButtonClick: async (e) => {
73
+ if (e !== ButtonNames.YES)
74
+ return;
75
+ let result = [];
76
+ try {
77
+ setCicoWaitPanelTitle(title);
78
+ setShowCicoWaitPanel(true);
79
+ setShowCicoPrimaryProgress(true);
80
+ abortController = new AbortController();
81
+ const ue = SDK_Globals.tmSession?.NewUpdateEngineByID();
82
+ if (!ue)
83
+ throw new Error("Update Engine not available");
84
+ ue.TID = dcmt.TID;
85
+ ue.DID = dcmt.DID;
86
+ if (checkout) {
87
+ await ue.CheckOutAsync()
88
+ .then(async () => {
89
+ await cicoDownloadFilesCallback([{ type: 'dcmtInfo', dcmtInfo: dcmt, originalFileName: filename }], true, downloadDcmtsAsync);
90
+ result.push({ rowIndex: 1, id1: dcmt.TID, id2: dcmt.DID, description: SDKUI_Localizator.UpdateCompletedSuccessfully, resultType: ResultTypes.SUCCESS });
91
+ await refreshMetadataAsync?.();
92
+ await refreshFocusedDataRowAsync?.(dcmt.TID, dcmt.DID, true);
93
+ })
94
+ .catch((error) => {
95
+ result.push({ rowIndex: 1, id1: dcmt.TID, id2: dcmt.DID, resultType: ResultTypes.ERROR, description: getExceptionMessage(error) });
96
+ throw error;
97
+ });
98
+ }
99
+ else {
100
+ await ue.UndoCheckOutAsync()
101
+ .then(async () => {
102
+ result.push({ rowIndex: 1, id1: dcmt.TID, id2: dcmt.DID, description: SDKUI_Localizator.UpdateCompletedSuccessfully, resultType: ResultTypes.SUCCESS });
103
+ // Remove the corresponding draft checkout item
104
+ updateCicoCheckoutStorageItem({ TID: dcmt.TID.toString(), DID: dcmt.DID.toString(), checkoutFolder: "", checkoutName: "" }, "dcmtInfo", "remove");
105
+ await refreshMetadataAsync?.();
106
+ await refreshFocusedDataRowAsync?.(dcmt.TID, dcmt.DID, true);
107
+ })
108
+ .catch((error) => {
109
+ result.push({ rowIndex: 0, id1: dcmt.TID, id2: dcmt.DID, resultType: ResultTypes.ERROR, description: getExceptionMessage(error) });
110
+ throw error;
111
+ });
112
+ }
113
+ }
114
+ catch (error) {
115
+ result.push({ rowIndex: 1, id1: dcmt.TID, id2: dcmt.DID, resultType: ResultTypes.ERROR, description: getExceptionMessage(error) });
116
+ }
117
+ finally {
118
+ setCicoPrimaryProgressText('');
119
+ setCicoPrimaryProgressMax(0);
120
+ setCicoPrimaryProgressValue(0);
121
+ setShowCicoWaitPanel(false);
122
+ TMResultManager.show(result, title, "ID", undefined);
123
+ }
124
+ }
125
+ });
126
+ };
127
+ const triggerCommentOnFileAdd = (addedFiles) => {
128
+ if (addedFiles.length > 0) {
129
+ setCommentFormState({
130
+ show: true,
131
+ isRequired: true,
132
+ removeAndEditAttachment: false
133
+ });
134
+ }
135
+ };
136
+ const handleCheckInCallback = async (dcmt, refreshMetadataAsync, refreshFocusedDataRowAsync) => {
137
+ if (!dcmt)
138
+ throw new Error("Document info is required");
139
+ // Create a new file input element
140
+ const input = document.createElement("input");
141
+ // Set the input type to "file" to allow file selection
142
+ input.type = "file";
143
+ // Set the accepted file types (e.g., images, PDFs, etc.)
144
+ input.accept = "*/*";
145
+ // Enable the input to accept one file at once
146
+ input.multiple = false;
147
+ // Add an event listener for when the file selection changes
148
+ input.addEventListener('change', async (event) => {
149
+ const fileInput = event.target;
150
+ if (!fileInput.files || fileInput.files.length === 0)
151
+ return;
152
+ const file = fileInput.files[0];
153
+ const validateFileName = validateCicoFileName({ type: 'dcmtInfo', dcmtInfo: dcmt, originalFileName: dcmt.fileName ?? SDKUI_Localizator.SearchResult }, file.name);
154
+ TMMessageBoxManager.show({
155
+ resizable: true,
156
+ buttons: [ButtonNames.YES, ButtonNames.NO],
157
+ message: renderCicoCheckInContent({ type: 'dcmtInfo', dcmtInfo: dcmt, originalFileName: dcmt.fileName ?? SDKUI_Localizator.SearchResult }, file, validateFileName.isValid, validateFileName.validationResults),
158
+ title: "Check in",
159
+ onButtonClick: async (e) => {
160
+ if (e !== ButtonNames.YES)
161
+ return;
162
+ setCicoWaitPanelTitle('Check in');
163
+ setShowCicoWaitPanel(true);
164
+ setShowCicoPrimaryProgress(true);
165
+ abortController = new AbortController();
166
+ let result = [];
167
+ let i = 0;
168
+ if (dcmt.TID && dcmt.DID) {
169
+ try {
170
+ const ue = SDK_Globals.tmSession?.NewUpdateEngineByID();
171
+ if (ue) {
172
+ ue.TID = dcmt.TID;
173
+ ue.DID = dcmt.DID;
174
+ await ue.CheckInAsync(file, "", abortController.signal);
175
+ // Remove the corresponding draft checkout item
176
+ updateCicoCheckoutStorageItem({ TID: dcmt.TID.toString(), DID: dcmt.DID.toString(), checkoutFolder: "", checkoutName: "" }, "dcmtInfo", "remove");
177
+ result.push({ rowIndex: i, id1: dcmt.DID, id2: dcmt.DID, description: SDKUI_Localizator.UpdateCompletedSuccessfully, resultType: ResultTypes.SUCCESS });
178
+ await refreshMetadataAsync?.();
179
+ await refreshFocusedDataRowAsync?.(dcmt.TID, dcmt.DID, true);
180
+ const cacheKey = `${dcmt.TID}-${dcmt.DID}`;
181
+ if (dcmtsFileCachePreview.has(cacheKey))
182
+ removeDcmtsFileCache(cacheKey);
183
+ triggerPreviewRefresh();
184
+ triggerCommentOnFileAdd([dcmt.DID]);
185
+ }
186
+ }
187
+ catch (err) {
188
+ result.push({ rowIndex: i, id1: i, id2: i, resultType: ResultTypes.ERROR, description: getExceptionMessage(err) });
189
+ }
190
+ finally {
191
+ setCicoPrimaryProgressText('');
192
+ setCicoPrimaryProgressMax(0);
193
+ setCicoPrimaryProgressValue(0);
194
+ setShowCicoWaitPanel(false);
195
+ TMResultManager.show(result, 'Check in', "ID", undefined, SDKUI_Localizator.CheckInSuccessMessage, 6000);
196
+ }
197
+ }
198
+ },
199
+ });
200
+ });
201
+ input.click();
202
+ };
203
+ return {
204
+ showHistory,
205
+ showHistoryCallback,
206
+ hideHistoryCallback,
207
+ showCheckoutInformationForm,
208
+ showCheckoutInformationFormCallback,
209
+ hideCheckoutInformationFormCallback,
210
+ commentFormState,
211
+ hideCommentFormCallback,
212
+ copyCheckoutPathToClipboardCallback,
213
+ handleCheckOutCallback,
214
+ handleCheckInCallback,
215
+ refreshPreviewTrigger,
216
+ showCicoWaitPanel,
217
+ cicoWaitPanelTitle,
218
+ showCicoPrimaryProgress,
219
+ cicoPrimaryProgressText,
220
+ cicoPrimaryProgressValue,
221
+ cicoPrimaryProgressMax,
222
+ };
223
+ };
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+ import { DataListItemDescriptor, DataListViewModes } from '@topconsultnpm/sdk-ts';
3
+ export declare const useDataListItem: () => {
4
+ loadDataListsAsync: (dataListIDs: Set<number>) => Promise<void>;
5
+ getDataListItem: (dataListID: number, value: string | number | Date) => DataListItemDescriptor | undefined;
6
+ clearCache: () => void;
7
+ hasDataList: (dataListID: number) => boolean;
8
+ renderDataListCell: (value: string | Date | number | undefined, dataListID: number, dataListViewMode: DataListViewModes) => React.ReactElement;
9
+ dataListsCache: React.MutableRefObject<Map<number, DataListItemDescriptor[]>>;
10
+ convertToDataListValue: (value: string | Date | number | undefined) => string;
11
+ convertToDataListDisplayValue: (value: string | Date | number | undefined) => string;
12
+ };
@@ -0,0 +1,131 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useRef, useCallback } from 'react';
3
+ import { DataListCacheService, DataListViewModes } from '@topconsultnpm/sdk-ts';
4
+ import { IconWarning, SDKUI_Localizator, TMImageLibrary } from '../helper';
5
+ import { FormulaHelper, StyledDivHorizontal } from '../components';
6
+ import { TMColors } from '../utils/theme';
7
+ export const useDataListItem = () => {
8
+ const dataListsCacheRef = useRef(new Map());
9
+ /**
10
+ * Converte un valore in formato stringa per DataList
11
+ * @param value Valore da convertire
12
+ * @returns Stringa rappresentante il valore
13
+ */
14
+ const convertToDataListValue = useCallback((value) => {
15
+ if (value instanceof Date) {
16
+ return value.toISOString();
17
+ }
18
+ else if (typeof value === 'number') {
19
+ return value.toString();
20
+ }
21
+ else {
22
+ return value ?? '';
23
+ }
24
+ }, []);
25
+ /**
26
+ * Converte un valore in formato stringa per visualizzazione in DataList
27
+ * @param value Valore da convertire
28
+ * @returns Stringa formattata per visualizzazione
29
+ */
30
+ const convertToDataListDisplayValue = useCallback((value) => {
31
+ if (value instanceof Date) {
32
+ return value.toLocaleDateString();
33
+ }
34
+ else if (typeof value === 'number') {
35
+ return value.toString();
36
+ }
37
+ else {
38
+ return value ?? '';
39
+ }
40
+ }, []);
41
+ /**
42
+ * Carica tutte le DataList necessarie in parallelo e popola la cache
43
+ * @param dataListIDs Set di ID delle DataList da caricare
44
+ * @returns Promise che si risolve quando tutte le DataList sono state caricate
45
+ */
46
+ const loadDataListsAsync = useCallback(async (dataListIDs) => {
47
+ if (dataListIDs.size === 0)
48
+ return;
49
+ try {
50
+ const results = await Promise.all(Array.from(dataListIDs).map(id => DataListCacheService.GetAsync(id).then(dl => ({
51
+ id,
52
+ items: dl?.items ?? []
53
+ }))));
54
+ const newCache = new Map();
55
+ results.forEach(({ id, items }) => newCache.set(id, items));
56
+ dataListsCacheRef.current = newCache;
57
+ }
58
+ catch (err) {
59
+ console.error('Error loading DataLists:', err);
60
+ dataListsCacheRef.current = new Map();
61
+ }
62
+ }, []);
63
+ /**
64
+ * Recupera un item dalla cache della DataList
65
+ * @param dataListID ID della DataList
66
+ * @param value Valore dell'item da cercare
67
+ * @returns DataListItemDescriptor se trovato, undefined altrimenti
68
+ */
69
+ const getDataListItem = useCallback((dataListID, value) => {
70
+ const stringValue = convertToDataListValue(value);
71
+ const dataListItems = dataListsCacheRef.current.get(dataListID);
72
+ return dataListItems?.find(o => o.value == stringValue);
73
+ }, []);
74
+ /**
75
+ * Svuota completamente la cache
76
+ */
77
+ const clearCache = useCallback(() => {
78
+ dataListsCacheRef.current = new Map();
79
+ }, []);
80
+ /**
81
+ * Verifica se una DataList è presente nella cache
82
+ * @param dataListID ID della DataList
83
+ * @returns true se la DataList è in cache, false altrimenti
84
+ */
85
+ const hasDataList = useCallback((dataListID) => {
86
+ return dataListsCacheRef.current.has(dataListID);
87
+ }, []);
88
+ /**
89
+ * Renderizza una cella DataList con icona e testo formattato
90
+ * @param value Valore della cella
91
+ * @param dataListID ID della DataList
92
+ * @param dataListViewMode Modalità di visualizzazione della DataList
93
+ * @returns Elemento React per la cella DataList
94
+ */
95
+ const renderDataListCell = useCallback((value, dataListID, dataListViewMode) => {
96
+ const stringValue = convertToDataListValue(value);
97
+ const showIcon = dataListViewMode !== DataListViewModes.Description;
98
+ const dataListItem = getDataListItem(dataListID, stringValue);
99
+ const getIcon = () => {
100
+ if (!showIcon)
101
+ return null;
102
+ if (value === undefined || value === null)
103
+ return null;
104
+ if (FormulaHelper.isFormula(stringValue))
105
+ return null;
106
+ return dataListItem
107
+ ? _jsx(TMImageLibrary, { imageID: dataListItem.imageID })
108
+ : _jsx(IconWarning, { color: TMColors.warning });
109
+ };
110
+ return (_jsxs(StyledDivHorizontal, { style: { width: '100%' }, title: dataListItem ? dataListItem.value : SDKUI_Localizator.ValueNotPresent, children: [getIcon(), _jsx("p", { style: {
111
+ textAlign: 'left',
112
+ marginLeft: showIcon ? '5px' : '',
113
+ opacity: dataListItem ? 1 : 0.5,
114
+ whiteSpace: 'nowrap',
115
+ overflow: 'hidden',
116
+ textOverflow: 'ellipsis',
117
+ flexGrow: 1,
118
+ minWidth: 0
119
+ }, children: dataListItem ? dataListItem.name : convertToDataListDisplayValue(value) })] }));
120
+ }, [getDataListItem]);
121
+ return {
122
+ loadDataListsAsync,
123
+ getDataListItem,
124
+ clearCache,
125
+ hasDataList,
126
+ renderDataListCell,
127
+ dataListsCache: dataListsCacheRef,
128
+ convertToDataListValue,
129
+ convertToDataListDisplayValue
130
+ };
131
+ };
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ import { UserDescriptor } from '@topconsultnpm/sdk-ts';
3
+ export declare const useDataUserIdItem: () => {
4
+ loadUsersAsync: (userIDs: Set<number>) => Promise<void>;
5
+ getUserItem: (userId: number) => UserDescriptor | undefined;
6
+ clearCache: () => void;
7
+ hasUser: (userId: number) => boolean;
8
+ usersCache: React.MutableRefObject<Map<number, UserDescriptor>>;
9
+ renderUserIdViewer: (userId: number | undefined, showIcon?: boolean, showTitile?: boolean) => React.ReactElement;
10
+ };
@@ -0,0 +1,96 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useRef, useCallback } from 'react';
3
+ import { UserListCacheService } from '@topconsultnpm/sdk-ts';
4
+ import { IconWarning, SDKUI_Localizator } from '../helper';
5
+ import { TMColors } from '../utils/theme';
6
+ import { TMUserIcon } from '../components';
7
+ export const useDataUserIdItem = () => {
8
+ const usersCacheRef = useRef(new Map());
9
+ /**
10
+ * Carica tutti gli utenti necessari in parallelo e popola la cache
11
+ * @param userIDs Set di ID degli utenti da caricare
12
+ * @returns Promise che si risolve quando tutti gli utenti sono stati caricati
13
+ */
14
+ const loadUsersAsync = useCallback(async (userIDs) => {
15
+ if (userIDs.size === 0)
16
+ return;
17
+ try {
18
+ const results = await Promise.all(Array.from(userIDs).map(id => UserListCacheService.GetAsync(id).then(user => ({ id, user }))
19
+ .catch(() => ({ id, user: undefined }))));
20
+ const newCache = new Map();
21
+ results.forEach(({ id, user }) => {
22
+ if (user)
23
+ newCache.set(id, user);
24
+ });
25
+ usersCacheRef.current = newCache;
26
+ }
27
+ catch (err) {
28
+ console.error('Error loading Users:', err);
29
+ usersCacheRef.current = new Map();
30
+ }
31
+ }, []);
32
+ /**
33
+ * Recupera un utente dalla cache
34
+ * @param userId ID dell'utente
35
+ * @returns UserDescriptor se trovato, undefined altrimenti
36
+ */
37
+ const getUserItem = useCallback((userId) => {
38
+ return usersCacheRef.current.get(userId);
39
+ }, []);
40
+ /**
41
+ * Svuota completamente la cache
42
+ */
43
+ const clearCache = useCallback(() => {
44
+ usersCacheRef.current = new Map();
45
+ }, []);
46
+ /**
47
+ * Verifica se un utente è presente nella cache
48
+ * @param userId ID dell'utente
49
+ * @returns true se l'utente è in cache, false altrimenti
50
+ */
51
+ const hasUser = useCallback((userId) => {
52
+ return usersCacheRef.current.has(userId);
53
+ }, []);
54
+ /**
55
+ * Helper per ottenere il nome completo dell'utente
56
+ */
57
+ const getCompleteUserName = useCallback((domain, name) => {
58
+ if (!name)
59
+ return undefined;
60
+ if (!domain)
61
+ return name;
62
+ return domain + "\\" + name;
63
+ }, []);
64
+ /**
65
+ * Renderizza un componente UserIdViewer
66
+ * @param userId ID dell'utente
67
+ * @param showIcon Se mostrare l'icona
68
+ * @param noneSelectionText Testo da mostrare quando non c'è selezione
69
+ * @param TMUserIcon Componente per l'icona utente
70
+ * @returns Elemento React per visualizzare l'utente
71
+ */
72
+ const renderUserIdViewer = useCallback((userId, showIcon = false, showTitile = true) => {
73
+ const ud = userId && userId > 0 ? getUserItem(userId) : undefined;
74
+ const getIcon = () => {
75
+ if (!showIcon)
76
+ return null;
77
+ if (!userId)
78
+ return null;
79
+ return ud ? _jsx(TMUserIcon, { ud: ud }) : _jsx("div", { title: showTitile ? SDKUI_Localizator.ValueNotPresent : undefined, children: _jsx(IconWarning, { color: TMColors.warning }) });
80
+ };
81
+ const getDescription = () => {
82
+ if (!userId)
83
+ return undefined;
84
+ return ud ? getCompleteUserName(ud.domain, ud.name) : userId.toString() ?? SDKUI_Localizator.NoneSelection;
85
+ };
86
+ return (_jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: '4px' }, children: [getIcon(), _jsx("span", { children: getDescription() })] }));
87
+ }, [getUserItem, getCompleteUserName]);
88
+ return {
89
+ loadUsersAsync,
90
+ getUserItem,
91
+ clearCache,
92
+ hasUser,
93
+ usersCache: usersCacheRef,
94
+ renderUserIdViewer
95
+ };
96
+ };
@@ -0,0 +1,11 @@
1
+ export interface SettingsFeedback {
2
+ showSavedBadge: boolean;
3
+ lastChanged: {
4
+ label: string;
5
+ value: string;
6
+ };
7
+ isWarning: boolean;
8
+ triggerUIUpdate: (label: string, value: any, warning?: boolean) => void;
9
+ closeBadge: () => void;
10
+ }
11
+ export declare const useSettingsFeedback: () => SettingsFeedback;
@@ -0,0 +1,38 @@
1
+ import { useState, useRef } from 'react';
2
+ export const useSettingsFeedback = () => {
3
+ const [, setForceUpdate] = useState(0);
4
+ const [showSavedBadge, setShowSavedBadge] = useState(false);
5
+ const [lastChanged, setLastChanged] = useState({
6
+ label: '',
7
+ value: ''
8
+ });
9
+ const [isWarning, setIsWarning] = useState(false);
10
+ const timeoutRef = useRef(null);
11
+ const triggerUIUpdate = (label, value, warning = false) => {
12
+ setForceUpdate((prev) => prev + 1);
13
+ setShowSavedBadge(true);
14
+ setLastChanged({ label, value: String(value) });
15
+ setIsWarning(warning);
16
+ if (timeoutRef.current) {
17
+ clearTimeout(timeoutRef.current);
18
+ }
19
+ timeoutRef.current = setTimeout(() => {
20
+ setShowSavedBadge(false);
21
+ timeoutRef.current = null;
22
+ }, 4000);
23
+ };
24
+ const closeBadge = () => {
25
+ setShowSavedBadge(false);
26
+ if (timeoutRef.current) {
27
+ clearTimeout(timeoutRef.current);
28
+ timeoutRef.current = null;
29
+ }
30
+ };
31
+ return {
32
+ showSavedBadge,
33
+ lastChanged,
34
+ isWarning,
35
+ triggerUIUpdate,
36
+ closeBadge
37
+ };
38
+ };
@@ -8,4 +8,8 @@ export declare const useWorkflowApprove: () => {
8
8
  isLoading: boolean;
9
9
  refreshWorkflowApprove: () => Promise<void>;
10
10
  totalDcmtsFound: number;
11
+ getWorkItemsByDID: (targetDID: number) => {
12
+ tid: number;
13
+ did: number;
14
+ }[];
11
15
  };
@@ -14,6 +14,19 @@ export const useWorkflowApprove = () => {
14
14
  const calculateTotalDcmtsFound = useCallback((data) => {
15
15
  return data.reduce((sum, item) => sum + (item.dcmtsFound || 0), 0);
16
16
  }, []);
17
+ /**
18
+ * Ottiene tutti i work items che corrispondono a un determinato DID.
19
+ * Restituisce un array di oggetti { tid, did }.
20
+ */
21
+ const getWorkItemsByDID = useCallback((targetDID) => {
22
+ return workflowApproveData
23
+ .flatMap(workflow => workflow.dtdResult?.rows ?? [])
24
+ .filter(dataRow => Number(dataRow?.[1]) === targetDID)
25
+ .map(dataRow => ({
26
+ tid: Number(dataRow[0]),
27
+ did: targetDID
28
+ }));
29
+ }, [workflowApproveData]);
17
30
  /**
18
31
  * Esegue il fetch dei dati dal workflow, aggiorna lo stato globale
19
32
  * e notifica gli altri componenti tramite un evento.
@@ -53,5 +66,5 @@ export const useWorkflowApprove = () => {
53
66
  window.removeEventListener('onWorkflowApproveChange', handleUpdate);
54
67
  };
55
68
  }, [calculateTotalDcmtsFound]);
56
- return { workflowApproveData, isLoading, refreshWorkflowApprove, totalDcmtsFound };
69
+ return { workflowApproveData, isLoading, refreshWorkflowApprove, totalDcmtsFound, getWorkItemsByDID };
57
70
  };
package/lib/index.d.ts CHANGED
@@ -9,4 +9,5 @@ export * from './hooks/useDcmtOperations';
9
9
  export * from './hooks/useResizeObserver';
10
10
  export * from './hooks/useWorkflowApprove';
11
11
  export * from './hooks/useRelatedDocuments';
12
+ export * from './hooks/useSettingsFeedback';
12
13
  export * from './services';
package/lib/index.js CHANGED
@@ -9,6 +9,7 @@ export * from './hooks/useDcmtOperations';
9
9
  export * from './hooks/useResizeObserver';
10
10
  export * from './hooks/useWorkflowApprove';
11
11
  export * from './hooks/useRelatedDocuments';
12
+ export * from './hooks/useSettingsFeedback';
12
13
  export * from './services';
13
14
  import config from 'devextreme/core/config';
14
15
  // DevExtreme License Key (valid for v25.1 and earlier versions)
package/lib/ts/types.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { ReactNode } from "react";
2
- import { FileFormats, ITopMediaSession, MetadataDescriptor, MetadataValueDescriptor, UserDescriptor, ValidationItem } from "@topconsultnpm/sdk-ts";
2
+ import { DataListItemDescriptor, FileFormats, ITopMediaSession, MetadataDescriptor, MetadataValueDescriptor, UserDescriptor, ValidationItem } from "@topconsultnpm/sdk-ts";
3
3
  import { ITMEditorBase } from "../components/base/TMEditorBase";
4
4
  import { IColumnProps } from "devextreme-react/data-grid";
5
5
  export declare enum FormModes {
@@ -310,3 +310,60 @@ export declare enum buildTypes {
310
310
  RTM = "RTM",
311
311
  PATCH = "PATCH"
312
312
  }
313
+ /**
314
+ * Descrive un'istanza di workflow per il contesto WorkflowCtrl.
315
+ * Contiene tutte le informazioni necessarie per recuperare i work items associati.
316
+ */
317
+ export interface WFInstanceDescriptor {
318
+ /** ID dell'istanza */
319
+ instanceId: string;
320
+ /** Indice della riga nel search result */
321
+ rowIndex: number;
322
+ /** Struttura metadati completa da searchResultToDataSource: { [key: string]: { md: MetadataDescriptor, value: any } } */
323
+ values: any;
324
+ /** TID del documento workflow */
325
+ tid?: number;
326
+ /** DID del documento workflow */
327
+ did?: number;
328
+ /** ID del workflow */
329
+ wfid?: number;
330
+ /** MID del metadato che contiene lo stato del workflow */
331
+ mStatusMID?: number;
332
+ /** DataList ID per visualizzare lo stato */
333
+ mStatusDLID?: number;
334
+ }
335
+ /**
336
+ * Dettaglio di un singolo work item
337
+ */
338
+ export interface WorkItemDetail {
339
+ wid: string;
340
+ tid: number;
341
+ did: number;
342
+ wfid: number;
343
+ approvalVID: number;
344
+ status?: DataListItemDescriptor;
345
+ setID: string;
346
+ response?: string;
347
+ creationTime?: Date;
348
+ completionTime?: Date;
349
+ from?: number;
350
+ to?: number;
351
+ toUser?: UserDescriptor;
352
+ or?: number;
353
+ }
354
+ /**
355
+ * Raggruppamento di work items per setID (e creationTime se lo step si ripete)
356
+ */
357
+ export interface IWorkItemData {
358
+ wid: string;
359
+ category?: any;
360
+ type?: any;
361
+ name?: string;
362
+ description?: string;
363
+ setID: string;
364
+ creationTime?: Date;
365
+ setStatus?: DataListItemDescriptor;
366
+ setRule?: number;
367
+ details: WorkItemDetail[];
368
+ groupIndex?: number;
369
+ }
@@ -57,7 +57,7 @@ declare class FontSize {
57
57
  static defaultFontSizeInPixel: string;
58
58
  }
59
59
  declare class TMMargin {
60
- static defultMargin: string;
60
+ static defaultMargin: string;
61
61
  static smallMargin: string;
62
62
  static largeMargin: string;
63
63
  }
@@ -65,7 +65,7 @@ FontSize.defaultFontSize = '1rem';
65
65
  FontSize.defaultFontSizeInPixel = '13px';
66
66
  class TMMargin {
67
67
  }
68
- TMMargin.defultMargin = '5px';
68
+ TMMargin.defaultMargin = '5px';
69
69
  TMMargin.smallMargin = '3px';
70
70
  TMMargin.largeMargin = '10px';
71
71
  class Gutters {