@topconsultnpm/sdkui-react 6.21.0-dev3.2 → 6.21.0-dev3.21

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 (51) hide show
  1. package/lib/components/NewComponents/ContextMenu/styles.d.ts +4 -4
  2. package/lib/components/NewComponents/FloatingMenuBar/styles.d.ts +2 -2
  3. package/lib/components/base/TMDataGrid.js +12 -2
  4. package/lib/components/base/TMDataGridExportForm.js +19 -8
  5. package/lib/components/base/TMFileManagerDataGridView.js +4 -4
  6. package/lib/components/base/TMFileManagerThumbnailItems.js +3 -3
  7. package/lib/components/base/TMFileManagerUtils.d.ts +7 -0
  8. package/lib/components/base/TMFileManagerUtils.js +14 -1
  9. package/lib/components/base/TMModal.js +2 -2
  10. package/lib/components/base/TMTreeView.js +12 -15
  11. package/lib/components/choosers/TMDynDataListItemChooser.js +6 -1
  12. package/lib/components/editors/TMEditorStyled.d.ts +6 -6
  13. package/lib/components/editors/TMMetadataEditor.js +6 -2
  14. package/lib/components/editors/TMMetadataValues.js +10 -2
  15. package/lib/components/features/blog/TMBlogCommentForm.js +5 -2
  16. package/lib/components/features/documents/TMCopyToFolderForm.js +2 -2
  17. package/lib/components/features/documents/TMDcmtIcon.js +1 -1
  18. package/lib/components/features/documents/TMMergeToPdfForm.js +2 -2
  19. package/lib/components/features/documents/TMRelationViewer.js +6 -1
  20. package/lib/components/features/documents/copyAndMergeDcmtsShared.d.ts +0 -13
  21. package/lib/components/features/documents/copyAndMergeDcmtsShared.js +1 -39
  22. package/lib/components/features/search/TMMetadataOutputForm.d.ts +17 -0
  23. package/lib/components/features/search/TMMetadataOutputForm.js +225 -0
  24. package/lib/components/features/search/TMMetadataSorterForm.d.ts +17 -0
  25. package/lib/components/features/search/TMMetadataSorterForm.js +243 -0
  26. package/lib/components/features/search/TMSearchQueryEditor.js +14 -8
  27. package/lib/components/features/search/TMSearchQueryPanel.js +249 -58
  28. package/lib/components/features/search/TMSearchResult.js +2 -3
  29. package/lib/components/features/search/TMViewHistoryDcmt.js +1 -1
  30. package/lib/components/features/search/metadataFormHelper.d.ts +16 -0
  31. package/lib/components/features/search/metadataFormHelper.js +77 -0
  32. package/lib/components/grids/TMBlogAttachments.js +2 -2
  33. package/lib/components/grids/TMBlogsPost.js +5 -3
  34. package/lib/components/grids/TMBlogsPostUtils.d.ts +1 -0
  35. package/lib/components/grids/TMBlogsPostUtils.js +3 -1
  36. package/lib/helper/MergePdfManager.js +7 -4
  37. package/lib/helper/SDKUI_Globals.js +2 -1
  38. package/lib/helper/SDKUI_Localizator.d.ts +4 -0
  39. package/lib/helper/SDKUI_Localizator.js +40 -0
  40. package/lib/helper/TMUtils.d.ts +23 -0
  41. package/lib/helper/TMUtils.js +55 -0
  42. package/lib/helper/checkinCheckoutManager.d.ts +4 -3
  43. package/lib/helper/checkinCheckoutManager.js +29 -11
  44. package/lib/hooks/useCheckInOutOperations.d.ts +4 -3
  45. package/lib/hooks/useDataUserIdItem.js +1 -1
  46. package/lib/hooks/useDcmtOperations.d.ts +18 -1
  47. package/lib/hooks/useDcmtOperations.js +67 -21
  48. package/lib/hooks/useDocumentOperations.js +3 -3
  49. package/lib/hooks/useRelatedDocuments.js +4 -4
  50. package/lib/services/platform_services.d.ts +4 -4
  51. package/package.json +10 -7
@@ -0,0 +1,243 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
3
+ import { OrderByItem, SDK_Localizator } from "@topconsultnpm/sdk-ts";
4
+ import { IconAddCircleOutline, IconApply, IconClear, IconDelete, IconDraggabledots, IconUndo, SDKUI_Localizator } from "../../../helper";
5
+ import TMToppyMessage from "../../../helper/TMToppyMessage";
6
+ import { ButtonNames, TMMessageBoxManager } from "../../base/TMPopUp";
7
+ import { TMColors } from "../../../utils/theme";
8
+ import { StyledToolbarForm } from "../../base/Styled";
9
+ import TMButton from "../../base/TMButton";
10
+ import TMModal from "../../base/TMModal";
11
+ import { TMMetadataChooserForm } from "../../choosers/TMMetadataChooser";
12
+ import TMDropDown from "../../editors/TMDropDown";
13
+ import { TMMetadataIcon } from "../../viewers/TMMidViewer";
14
+ import { loadMetadataFromQd, removeDuplicatesByTidMid, areArraysEqual } from "./metadataFormHelper";
15
+ const TMMetadataSorterForm = (props) => {
16
+ const { qd, selectedOrderByItems, allowSysMetadata = true, filterMetadata, onClose, onChoose } = props;
17
+ // =============================================================================
18
+ // STATE
19
+ // =============================================================================
20
+ // Stato iniziale degli OrderByItem (per confronto isModified)
21
+ const initialOrderByItemsRef = useRef((selectedOrderByItems ?? []).map(item => {
22
+ const newItem = new OrderByItem();
23
+ newItem.tid = item.tid;
24
+ newItem.mid = item.mid;
25
+ newItem.asc = item.asc ?? true;
26
+ return newItem;
27
+ }));
28
+ // Lista degli OrderByItem correnti (inizializzata da selectedOrderByItems)
29
+ const [orderByItems, setOrderByItems] = useState(() => {
30
+ // Clona gli OrderByItem iniziali per evitare mutazioni
31
+ return (selectedOrderByItems ?? []).map(item => {
32
+ const newItem = new OrderByItem();
33
+ newItem.tid = item.tid;
34
+ newItem.mid = item.mid;
35
+ newItem.asc = item.asc ?? true;
36
+ return newItem;
37
+ });
38
+ });
39
+ // Calcola se ci sono modifiche rispetto allo stato iniziale
40
+ const isModified = useMemo(() => {
41
+ return !areArraysEqual(orderByItems, initialOrderByItemsRef.current, (a, b) => a.asc === b.asc);
42
+ }, [orderByItems]);
43
+ // Lista "piatta" di tutti i metadati estratti dai DTD, con chiave univoca
44
+ const [metadataList, setMetadataList] = useState([]);
45
+ // Flag di caricamento
46
+ const [isLoading, setIsLoading] = useState(true);
47
+ // Flag per mostrare il TMMetadataChooserForm
48
+ const [showMetadataChooser, setShowMetadataChooser] = useState(false);
49
+ // Item in fase di drag
50
+ const [draggingItem, setDraggingItem] = useState(undefined);
51
+ // =============================================================================
52
+ // MEMOIZZAZIONI per evitare re-render del TMMetadataChooserForm
53
+ // =============================================================================
54
+ // Lista di TID_MID già selezionati (per escluderli dal chooser)
55
+ const selectedIDs = useMemo(() => orderByItems.map(oi => ({ tid: oi.tid, mid: oi.mid })), [orderByItems]);
56
+ // Callback per chiudere il chooser
57
+ const handleCloseChooser = useCallback(() => {
58
+ setShowMetadataChooser(false);
59
+ }, []);
60
+ // =============================================================================
61
+ // EFFECT: Carica i metadati al mount
62
+ // =============================================================================
63
+ useEffect(() => {
64
+ const load = async () => {
65
+ setIsLoading(true);
66
+ try {
67
+ const { metadata } = await loadMetadataFromQd(qd, filterMetadata);
68
+ setMetadataList(metadata);
69
+ }
70
+ catch (error) {
71
+ console.error("Errore nel caricamento dei metadati:", error);
72
+ setMetadataList([]);
73
+ }
74
+ finally {
75
+ setIsLoading(false);
76
+ }
77
+ };
78
+ load();
79
+ }, [qd, filterMetadata]);
80
+ // =============================================================================
81
+ // HELPER: Trova il MetadataDescriptor per un OrderByItem
82
+ // =============================================================================
83
+ const getMetadataForOrderByItem = useCallback((item) => {
84
+ return metadataList.find(md => md.customData1 === item.tid && md.id === item.mid);
85
+ }, [metadataList]);
86
+ // =============================================================================
87
+ // HANDLER: Conferma la scelta dal chooser (sincronizza la lista completa)
88
+ // =============================================================================
89
+ const handleChooseFromChooser = useCallback((tid_mids) => {
90
+ // Se la lista è vuota o undefined, rimuovi tutti
91
+ if (!tid_mids || tid_mids.length === 0) {
92
+ setOrderByItems([]);
93
+ setShowMetadataChooser(false);
94
+ return;
95
+ }
96
+ setOrderByItems(prev => {
97
+ // Filtra quelli esistenti che sono ancora selezionati (mantenendo ordine e impostazioni asc/desc)
98
+ const kept = prev.filter(oi => tid_mids.some(tm => tm.tid === oi.tid && tm.mid === oi.mid));
99
+ // Trova i nuovi da aggiungere
100
+ const newItems = [];
101
+ for (const tm of tid_mids) {
102
+ const exists = prev.some(oi => oi.tid === tm.tid && oi.mid === tm.mid);
103
+ if (!exists) {
104
+ const newItem = new OrderByItem();
105
+ newItem.tid = tm.tid;
106
+ newItem.mid = tm.mid;
107
+ newItem.asc = true;
108
+ newItems.push(newItem);
109
+ }
110
+ }
111
+ return removeDuplicatesByTidMid([...kept, ...newItems]);
112
+ });
113
+ setShowMetadataChooser(false);
114
+ }, []);
115
+ // =============================================================================
116
+ // HANDLER: Rimuove un ordinamento
117
+ // =============================================================================
118
+ const handleRemoveOrderBy = useCallback((index) => {
119
+ setOrderByItems(prev => prev.filter((_, i) => i !== index));
120
+ }, []);
121
+ // =============================================================================
122
+ // HANDLER: Toggle ascendente/discendente
123
+ // =============================================================================
124
+ const handleChangeAsc = useCallback((index, asc) => {
125
+ setOrderByItems(prev => prev.map((item, i) => {
126
+ if (i !== index)
127
+ return item;
128
+ const newItem = new OrderByItem();
129
+ newItem.tid = item.tid;
130
+ newItem.mid = item.mid;
131
+ newItem.asc = asc;
132
+ return newItem;
133
+ }));
134
+ }, []);
135
+ // =============================================================================
136
+ // DRAG & DROP HANDLERS
137
+ // =============================================================================
138
+ const handleDragStart = useCallback((e, item) => {
139
+ // Previeni il drag se il target è l'icona elimina o il dropdown
140
+ const target = e.target;
141
+ if (target.closest('[data-no-drag="true"]')) {
142
+ e.preventDefault();
143
+ return;
144
+ }
145
+ setDraggingItem(item);
146
+ e.dataTransfer.setData('text/plain', '');
147
+ e.dataTransfer.effectAllowed = 'move';
148
+ }, []);
149
+ const handleDragEnd = useCallback(() => {
150
+ setDraggingItem(undefined);
151
+ }, []);
152
+ const handleDragOver = useCallback((e) => {
153
+ e.preventDefault();
154
+ e.dataTransfer.dropEffect = 'move';
155
+ }, []);
156
+ const handleDrop = useCallback((e, targetItem) => {
157
+ e.preventDefault();
158
+ if (!draggingItem)
159
+ return;
160
+ const currentIndex = orderByItems.indexOf(draggingItem);
161
+ const targetIndex = orderByItems.indexOf(targetItem);
162
+ if (currentIndex === -1 || targetIndex === -1 || currentIndex === targetIndex) {
163
+ setDraggingItem(undefined);
164
+ return;
165
+ }
166
+ const listCopy = [...orderByItems];
167
+ listCopy.splice(currentIndex, 1);
168
+ listCopy.splice(targetIndex, 0, draggingItem);
169
+ setOrderByItems(listCopy);
170
+ setDraggingItem(undefined);
171
+ }, [draggingItem, orderByItems]);
172
+ // =============================================================================
173
+ // HANDLER: Rollback allo stato iniziale
174
+ // =============================================================================
175
+ const handleRollback = useCallback(() => {
176
+ setOrderByItems(initialOrderByItemsRef.current.map(item => {
177
+ const newItem = new OrderByItem();
178
+ newItem.tid = item.tid;
179
+ newItem.mid = item.mid;
180
+ newItem.asc = item.asc;
181
+ return newItem;
182
+ }));
183
+ }, []);
184
+ // =============================================================================
185
+ // HANDLER: Chiusura con conferma se modificato
186
+ // =============================================================================
187
+ const confirmCloseContainerId = "TMMetadataSorterFormConfirmClose";
188
+ const handleClose = useCallback(() => {
189
+ if (!isModified) {
190
+ onClose();
191
+ return;
192
+ }
193
+ TMMessageBoxManager.show({
194
+ parentId: confirmCloseContainerId,
195
+ message: SDKUI_Localizator.ConfirmOnCancel,
196
+ buttons: [ButtonNames.YES, ButtonNames.NO],
197
+ onButtonClick: (buttonClicked) => {
198
+ if (buttonClicked === ButtonNames.YES) {
199
+ onClose();
200
+ }
201
+ }
202
+ });
203
+ }, [isModified, onClose]);
204
+ // =============================================================================
205
+ // HANDLER: Conferma la selezione
206
+ // =============================================================================
207
+ const handleConfirm = useCallback(() => {
208
+ onChoose?.(orderByItems.length > 0 ? orderByItems : undefined);
209
+ onClose();
210
+ }, [orderByItems, onChoose, onClose]);
211
+ // =============================================================================
212
+ // RENDER
213
+ // =============================================================================
214
+ return (_jsxs(_Fragment, { children: [_jsxs(TMModal, { title: `${SDKUI_Localizator.Configure} - ${SDK_Localizator.QueryOrderBy}${orderByItems.length > 0 ? ` (${orderByItems.length})` : ''}`, width: "600px", height: "500px", onClose: handleClose, hidePopup: false, askClosingConfirm: isModified, children: [_jsx("div", { id: confirmCloseContainerId }), _jsxs("div", { style: { display: 'flex', flexDirection: 'column', height: '100%', gap: '10px' }, children: [_jsxs(StyledToolbarForm, { children: [_jsx(TMButton, { caption: SDKUI_Localizator.Confirm, icon: _jsx(IconApply, {}), btnStyle: "toolbar", color: "success", disabled: !isModified, onClick: handleConfirm }), _jsx(TMButton, { caption: SDKUI_Localizator.Undo, icon: _jsx(IconUndo, {}), btnStyle: "toolbar", color: "tertiary", disabled: !isModified, onClick: handleRollback }), _jsx(TMButton, { caption: SDKUI_Localizator.Add, icon: _jsx(IconAddCircleOutline, {}), btnStyle: "toolbar", onClick: () => setShowMetadataChooser(true) }), _jsx(TMButton, { caption: SDKUI_Localizator.Clear, icon: _jsx(IconClear, {}), btnStyle: "toolbar", disabled: orderByItems.length === 0, onClick: () => setOrderByItems([]) })] }), _jsxs("div", { style: {
215
+ flex: 1,
216
+ overflow: 'auto',
217
+ border: `1px solid ${TMColors.border_normal}`,
218
+ borderRadius: '4px',
219
+ padding: '5px'
220
+ }, children: [isLoading && _jsxs("p", { style: { textAlign: 'center', padding: '20px' }, children: [SDKUI_Localizator.Loading, "..."] }), !isLoading && orderByItems.length === 0 && (_jsx(TMToppyMessage, { message: SDKUI_Localizator.NoSortingApplied, titleTooltip: SDKUI_Localizator.NoSortingApplied })), !isLoading && orderByItems.length > 0 && (_jsx("div", { style: { display: 'flex', flexDirection: 'column', gap: '2px' }, children: orderByItems.map((item, index) => {
221
+ const md = getMetadataForOrderByItem(item);
222
+ const isDragging = draggingItem === item;
223
+ return (_jsxs("div", { draggable: true, onDragStart: (e) => handleDragStart(e, item), onDragEnd: handleDragEnd, onDragOver: handleDragOver, onDrop: (e) => handleDrop(e, item), style: {
224
+ display: 'flex',
225
+ alignItems: 'center',
226
+ gap: '6px',
227
+ padding: '4px 8px',
228
+ backgroundColor: isDragging ? TMColors.primary_container : TMColors.default_background,
229
+ borderRadius: '3px',
230
+ border: `1px solid ${isDragging ? TMColors.primaryColor : TMColors.border_normal}`,
231
+ minHeight: '32px',
232
+ cursor: 'grab',
233
+ transition: 'all 0.2s ease',
234
+ transform: isDragging ? 'scale(1.02)' : 'scale(1)',
235
+ boxShadow: isDragging ? '0 4px 12px rgba(0,0,0,0.15)' : 'none',
236
+ opacity: isDragging ? 0.9 : 1,
237
+ }, children: [_jsx("div", { style: { display: 'flex', cursor: 'grab' }, children: _jsx(IconDraggabledots, { fontSize: 15, color: TMColors.button_icon }) }), _jsx(TMMetadataIcon, { tid: item.tid ?? 0, md: md }), _jsx("span", { style: { flex: 1, fontSize: '13px', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }, children: md?.name ?? `MID: ${item.mid}` }), _jsx("div", { "data-no-drag": "true", onMouseDown: (e) => e.stopPropagation(), children: _jsx(TMDropDown, { width: "175px", height: "28px", value: item.asc ? 'asc' : 'desc', dataSource: [
238
+ { value: 'asc', display: SDKUI_Localizator.ValueAscending },
239
+ { value: 'desc', display: SDKUI_Localizator.ValueDescending }
240
+ ], onValueChanged: (e) => handleChangeAsc(index, e.target.value === 'asc') }) }), _jsx("div", { "data-no-drag": "true", onMouseDown: (e) => e.stopPropagation(), children: _jsx(TMButton, { caption: SDKUI_Localizator.Remove, icon: _jsx(IconDelete, { color: TMColors.error }), btnStyle: "icon", onClick: () => handleRemoveOrderBy(index) }) })] }, `${item.tid}_${item.mid}_${index}`));
241
+ }) }))] })] })] }), showMetadataChooser && (_jsx(TMMetadataChooserForm, { allowMultipleSelection: true, height: "600px", width: "700px", allowSysMetadata: allowSysMetadata, filterMetadata: filterMetadata, qd: qd, selectedIDs: selectedIDs, onClose: handleCloseChooser, onChoose: handleChooseFromChooser }))] }));
242
+ };
243
+ export default TMMetadataSorterForm;
@@ -148,17 +148,23 @@ const TMSearchWhereItemEditor = React.memo(({ whereItem, queryParamsDynDataList,
148
148
  let dtd = await DcmtTypeListCacheService.GetAsync(whereItem.tid, true);
149
149
  return dtd?.metadata?.find(o => o.id === whereItem.mid);
150
150
  };
151
- // Rimuove gli apici singoli da valori separati da virgola: 'msegato','plevolella' -> msegato,plevolella
151
+ // Rimuove gli apici singoli da valori separati da virgola: 'val1','val2' -> val1,val2
152
+ // Applica trim solo ai valori quotati, preservando gli spazi nei valori non quotati
152
153
  const stripQuotes = (value) => {
153
154
  if (!value || typeof value !== 'string')
154
155
  return value;
155
- return value.split(',').map(item => {
156
- const trimmed = item.trim();
157
- if (trimmed.startsWith("'") && trimmed.endsWith("'")) {
158
- return trimmed.slice(1, -1);
159
- }
160
- return trimmed;
161
- }).join(',');
156
+ try {
157
+ return value.split(',').map(item => {
158
+ const trimmed = item.trim();
159
+ if (trimmed.startsWith("'") && trimmed.endsWith("'")) {
160
+ return trimmed.slice(1, -1); // trim + rimuovi apici
161
+ }
162
+ return item; // mantieni originale (con spazi)
163
+ }).join(',');
164
+ }
165
+ catch {
166
+ return value; // in caso di errore, ritorna il valore iniziale
167
+ }
162
168
  };
163
169
  const normalizeValue = (value, isForValue1 = true) => {
164
170
  let newValues = [];