@topconsultnpm/sdkui-react 6.19.0-dev2.9 → 6.19.0-test2

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 (97) hide show
  1. package/lib/components/base/TMAccordionNew.d.ts +28 -0
  2. package/lib/components/base/TMAccordionNew.js +326 -0
  3. package/lib/components/base/TMButton.d.ts +1 -0
  4. package/lib/components/base/TMButton.js +6 -6
  5. package/lib/components/base/TMCustomButton.d.ts +1 -1
  6. package/lib/components/base/TMCustomButton.js +83 -28
  7. package/lib/components/base/TMDataGridExportForm.js +9 -3
  8. package/lib/components/base/TMFileManager.js +11 -2
  9. package/lib/components/base/TMFileManagerDataGridView.d.ts +2 -0
  10. package/lib/components/base/TMFileManagerDataGridView.js +12 -3
  11. package/lib/components/base/TMFileManagerThumbnailItems.d.ts +2 -0
  12. package/lib/components/base/TMFileManagerThumbnailItems.js +12 -2
  13. package/lib/components/base/TMFileManagerThumbnailsView.d.ts +2 -0
  14. package/lib/components/base/TMFileManagerThumbnailsView.js +2 -2
  15. package/lib/components/base/TMModal.d.ts +2 -0
  16. package/lib/components/base/TMModal.js +48 -3
  17. package/lib/components/base/TMPopUp.js +74 -5
  18. package/lib/components/base/TMWaitPanel.js +8 -2
  19. package/lib/components/choosers/TMDataListItemChooser.js +1 -1
  20. package/lib/components/choosers/TMDcmtTypeChooser.js +2 -2
  21. package/lib/components/choosers/TMMetadataChooser.d.ts +4 -1
  22. package/lib/components/choosers/TMMetadataChooser.js +31 -8
  23. package/lib/components/choosers/TMUserChooser.d.ts +4 -0
  24. package/lib/components/choosers/TMUserChooser.js +21 -5
  25. package/lib/components/editors/TMMetadataValues.js +45 -4
  26. package/lib/components/editors/TMTextArea.d.ts +1 -0
  27. package/lib/components/editors/TMTextArea.js +44 -10
  28. package/lib/components/editors/TMTextBox.js +34 -4
  29. package/lib/components/editors/TMTextExpression.js +36 -28
  30. package/lib/components/features/assistant/ToppyDraggableHelpCenter.d.ts +30 -0
  31. package/lib/components/features/assistant/ToppyDraggableHelpCenter.js +471 -0
  32. package/lib/components/features/assistant/ToppySpeechBubble.d.ts +9 -0
  33. package/lib/components/features/assistant/ToppySpeechBubble.js +117 -0
  34. package/lib/components/features/blog/TMBlogCommentForm.d.ts +2 -0
  35. package/lib/components/features/blog/TMBlogCommentForm.js +18 -6
  36. package/lib/components/features/documents/TMDcmtBlog.js +1 -1
  37. package/lib/components/features/documents/TMDcmtForm.js +290 -31
  38. package/lib/components/features/documents/TMDcmtIcon.js +9 -4
  39. package/lib/components/features/documents/TMDcmtPreview.js +45 -8
  40. package/lib/components/features/documents/TMRelationViewer.js +55 -22
  41. package/lib/components/features/search/TMSearch.js +2 -2
  42. package/lib/components/features/search/TMSearchQueryEditor.js +1 -1
  43. package/lib/components/features/search/TMSearchQueryPanel.js +10 -28
  44. package/lib/components/features/search/TMSearchResult.js +102 -33
  45. package/lib/components/features/search/TMSearchResultsMenuItems.d.ts +2 -1
  46. package/lib/components/features/search/TMSearchResultsMenuItems.js +67 -28
  47. package/lib/components/features/search/TMSignSettingsForm.d.ts +9 -0
  48. package/lib/components/features/search/TMSignSettingsForm.js +621 -0
  49. package/lib/components/features/tasks/TMTaskForm.js +10 -4
  50. package/lib/components/features/tasks/TMTasksAgenda.js +1 -1
  51. package/lib/components/features/tasks/TMTasksCalendar.js +1 -1
  52. package/lib/components/features/tasks/TMTasksUtils.d.ts +1 -0
  53. package/lib/components/features/tasks/TMTasksUtils.js +17 -2
  54. package/lib/components/features/tasks/TMTasksUtilsView.js +26 -4
  55. package/lib/components/features/tasks/TMTasksView.js +11 -5
  56. package/lib/components/features/workflow/TMWorkflowPopup.js +3 -3
  57. package/lib/components/features/workflow/diagram/WFDiagram.js +19 -1
  58. package/lib/components/forms/TMSaveForm.js +3 -11
  59. package/lib/components/grids/TMBlogAttachments.d.ts +0 -14
  60. package/lib/components/grids/TMBlogAttachments.js +10 -5
  61. package/lib/components/grids/TMBlogsPost.d.ts +8 -3
  62. package/lib/components/grids/TMBlogsPost.js +100 -39
  63. package/lib/components/grids/TMBlogsPostUtils.d.ts +1 -0
  64. package/lib/components/grids/TMBlogsPostUtils.js +27 -6
  65. package/lib/components/index.d.ts +2 -1
  66. package/lib/components/index.js +2 -1
  67. package/lib/components/layout/panelManager/TMPanelManagerContainer.d.ts +1 -0
  68. package/lib/components/layout/panelManager/TMPanelManagerContainer.js +2 -2
  69. package/lib/components/layout/panelManager/TMPanelManagerContext.js +0 -1
  70. package/lib/components/layout/panelManager/TMPanelManagerToolbar.js +2 -1
  71. package/lib/components/layout/panelManager/types.d.ts +1 -0
  72. package/lib/components/settings/SettingsAppearance.js +5 -5
  73. package/lib/helper/GlobalStyles.d.ts +2 -0
  74. package/lib/helper/GlobalStyles.js +10 -0
  75. package/lib/helper/Globalization.d.ts +1 -0
  76. package/lib/helper/Globalization.js +30 -0
  77. package/lib/helper/SDKUI_Localizator.d.ts +41 -1
  78. package/lib/helper/SDKUI_Localizator.js +410 -10
  79. package/lib/helper/TMIcons.d.ts +4 -1
  80. package/lib/helper/TMIcons.js +13 -1
  81. package/lib/helper/TMToppyMessage.d.ts +1 -0
  82. package/lib/helper/TMToppyMessage.js +4 -3
  83. package/lib/helper/TMUtils.d.ts +42 -4
  84. package/lib/helper/TMUtils.js +190 -23
  85. package/lib/helper/dcmtsHelper.d.ts +2 -1
  86. package/lib/helper/dcmtsHelper.js +56 -17
  87. package/lib/helper/helpers.d.ts +1 -1
  88. package/lib/helper/helpers.js +12 -17
  89. package/lib/helper/index.d.ts +1 -0
  90. package/lib/helper/index.js +1 -0
  91. package/lib/hooks/useDcmtOperations.d.ts +1 -1
  92. package/lib/hooks/useDcmtOperations.js +10 -6
  93. package/lib/hooks/useRelatedDocuments.js +35 -26
  94. package/lib/ts/types.d.ts +2 -0
  95. package/package.json +8 -8
  96. package/lib/components/features/assistant/ToppyHelpCenter.d.ts +0 -12
  97. package/lib/components/features/assistant/ToppyHelpCenter.js +0 -173
@@ -0,0 +1,28 @@
1
+ import React from 'react';
2
+ export interface TMAccordionBadge {
3
+ badge: number;
4
+ tooltip?: string;
5
+ }
6
+ export interface TMAccordionGroup {
7
+ id: string;
8
+ title: string;
9
+ dataSource?: Array<any>;
10
+ color?: string;
11
+ icon?: React.ReactNode;
12
+ isExpanded?: boolean;
13
+ contextMenuItems?: Array<any> | ((item: any) => Array<any>);
14
+ onItemClick?: (item: any) => void;
15
+ onItemDoubleClick?: (item: any) => void;
16
+ renderItem?: (item: any, isSelected: boolean, isFocused: boolean, color: string) => React.ReactNode;
17
+ itemHeight?: number;
18
+ badges?: TMAccordionBadge[];
19
+ customComponent?: React.ReactNode;
20
+ }
21
+ export interface TMAccordionProps {
22
+ groups?: Array<TMAccordionGroup>;
23
+ localStorageKey?: string;
24
+ selectedItem?: any;
25
+ onSelectedItemChange?: (item: any) => void;
26
+ }
27
+ declare const TMAccordion: React.FC<TMAccordionProps>;
28
+ export default TMAccordion;
@@ -0,0 +1,326 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useState, useEffect, useCallback } from 'react';
3
+ import styled from 'styled-components';
4
+ import { ContextMenu, LoadIndicator } from 'devextreme-react';
5
+ import { LocalStorageService } from '@topconsultnpm/sdk-ts';
6
+ import TMTooltip from './TMTooltip';
7
+ const Container = styled.div `
8
+ width: 100%;
9
+ height: 100%;
10
+ overflow-y: auto;
11
+ overflow-x: hidden;
12
+ padding: 5px;
13
+
14
+ &::-webkit-scrollbar {
15
+ width: 8px;
16
+ }
17
+
18
+ &::-webkit-scrollbar-track {
19
+ background: #f1f3f5;
20
+ border-radius: 4px;
21
+ }
22
+
23
+ &::-webkit-scrollbar-thumb {
24
+ background: #adb5bd;
25
+ border-radius: 4px;
26
+
27
+ &:hover {
28
+ background: #868e96;
29
+ }
30
+ }
31
+
32
+ &::before {
33
+ content: '';
34
+ position: absolute;
35
+ top: 0;
36
+ left: 0;
37
+ right: 0;
38
+ bottom: 0;
39
+ z-index: -1;
40
+ }
41
+ `;
42
+ const AccordionItem = styled.div `
43
+ margin-bottom: 16px;
44
+ border-radius: 5px;
45
+ background: white;
46
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
47
+ overflow: hidden;
48
+ transition: box-shadow 0.3s ease;
49
+
50
+ &:hover {
51
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
52
+ }
53
+ `;
54
+ const AccordionHeader = styled.div `
55
+ display: flex;
56
+ align-items: center;
57
+ justify-content: space-between;
58
+ padding: 6px 12px;
59
+ background: ${props => `linear-gradient(135deg, ${props.$color}15 0%, ${props.$color}08 100%)`};
60
+ border-left: 4px solid ${props => props.$color};
61
+ cursor: pointer;
62
+ transition: all 0.3s ease;
63
+
64
+ &:hover {
65
+ background: ${props => `linear-gradient(135deg, ${props.$color}25 0%, ${props.$color}15 100%)`};
66
+ }
67
+ `;
68
+ const AccordionTitle = styled.div `
69
+ display: flex;
70
+ align-items: center;
71
+ gap: 8px;
72
+ flex: 1;
73
+ `;
74
+ const TitleText = styled.h3 `
75
+ margin: 0;
76
+ font-size: 14px;
77
+ font-weight: 600;
78
+ color: #212529;
79
+ display: flex;
80
+ align-items: center;
81
+ gap: 6px;
82
+ `;
83
+ const BadgeContainer = styled.div `
84
+ display: flex;
85
+ align-items: center;
86
+ gap: 6px;
87
+ `;
88
+ const Badge = styled.div `
89
+ min-width: 22px;
90
+ height: 22px;
91
+ padding: 0 8px;
92
+ display: flex;
93
+ align-items: center;
94
+ justify-content: center;
95
+ background: ${props => props.$color};
96
+ color: white;
97
+ border-radius: 11px;
98
+ font-size: 11px;
99
+ font-weight: 700;
100
+ box-shadow: 0 2px 6px ${props => props.$color}40;
101
+ `;
102
+ const CustomComponentContainer = styled.div `
103
+ padding: 8px;
104
+ `;
105
+ const ErrorMessage = styled.div `
106
+ padding: 20px;
107
+ text-align: center;
108
+ color: #fa5252;
109
+ font-size: 14px;
110
+ font-weight: 500;
111
+ `;
112
+ const ToggleIcon = styled.div `
113
+ width: 24px;
114
+ height: 24px;
115
+ display: flex;
116
+ align-items: center;
117
+ justify-content: center;
118
+ background: white;
119
+ border-radius: 6px;
120
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
121
+ transform: ${props => props.$isOpen ? 'rotate(180deg)' : 'rotate(0deg)'};
122
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
123
+ `;
124
+ const AccordionContent = styled.div `
125
+ max-height: ${props => props.$isOpen ? `${props.$maxHeight}px` : '0'};
126
+ overflow: hidden;
127
+ transition: max-height 0.4s cubic-bezier(0.4, 0, 0.2, 1);
128
+ `;
129
+ const ItemsList = styled.div `
130
+ padding: 4px;
131
+ `;
132
+ const ListItem = styled.div `
133
+ padding: 2px;
134
+ margin: 2px 0;
135
+ border-radius: 6px;
136
+ background: ${props => props.$isSelected ? `${props.$color}30` : 'transparent'};
137
+ border: none;
138
+ transition: background 0.2s ease;
139
+ cursor: pointer;
140
+
141
+ &:hover {
142
+ background: ${props => props.$isSelected ? `${props.$color}40` : `${props.$color}08`};
143
+ }
144
+ `;
145
+ const LoadingContainer = styled.div `
146
+ width: 100%;
147
+ height: 100%;
148
+ display: flex;
149
+ align-items: center;
150
+ justify-content: center;
151
+ min-height: 200px;
152
+ `;
153
+ const DEFAULT_COLORS = ['#339af0', '#fa5252', '#40c057', '#f59f00', '#e64980', '#7950f2'];
154
+ const TMAccordion = ({ groups, localStorageKey, selectedItem, onSelectedItemChange }) => {
155
+ const [openAccordions, setOpenAccordions] = useState({});
156
+ const [isInitialized, setIsInitialized] = useState(false);
157
+ const [anchorEl, setAnchorEl] = useState(null);
158
+ const [contextMenuItems, setContextMenuItems] = useState([]);
159
+ const [focusedItem, setFocusedItem] = useState(undefined);
160
+ const [headerContextGroupId, setHeaderContextGroupId] = useState(null);
161
+ const [headerContextVisible, setHeaderContextVisible] = useState(false);
162
+ const [headerContextPosition, setHeaderContextPosition] = useState(null);
163
+ useEffect(() => {
164
+ const initialState = {};
165
+ if (!groups || groups.length === 0) {
166
+ setIsInitialized(true);
167
+ return;
168
+ }
169
+ if (localStorageKey) {
170
+ const savedState = LocalStorageService.getItem(localStorageKey);
171
+ if (savedState && savedState.length === groups.length) {
172
+ groups.forEach((group, index) => {
173
+ initialState[group.id] = savedState[index] === '1';
174
+ });
175
+ }
176
+ else {
177
+ groups.forEach(group => {
178
+ initialState[group.id] = group.isExpanded !== false;
179
+ });
180
+ }
181
+ }
182
+ else {
183
+ groups.forEach(group => {
184
+ initialState[group.id] = group.isExpanded !== false;
185
+ });
186
+ }
187
+ setOpenAccordions(initialState);
188
+ setIsInitialized(true);
189
+ }, []);
190
+ useEffect(() => {
191
+ if (!isInitialized || !groups)
192
+ return;
193
+ setOpenAccordions(prev => {
194
+ const newState = { ...prev };
195
+ groups.forEach(group => {
196
+ if (!(group.id in newState)) {
197
+ newState[group.id] = group.isExpanded !== false;
198
+ }
199
+ });
200
+ Object.keys(newState).forEach(groupId => {
201
+ if (!groups.some(g => g.id === groupId)) { //nosonar
202
+ delete newState[groupId];
203
+ }
204
+ });
205
+ return newState;
206
+ });
207
+ }, [groups, isInitialized]);
208
+ useEffect(() => {
209
+ if (!isInitialized || !groups)
210
+ return;
211
+ if (localStorageKey && Object.keys(openAccordions).length === groups.length) {
212
+ const stateString = groups.map(group => openAccordions[group.id] ? '1' : '0').join('');
213
+ LocalStorageService.setItem(localStorageKey, stateString);
214
+ }
215
+ }, [openAccordions, groups, localStorageKey, isInitialized]);
216
+ const toggleAccordion = (groupId) => {
217
+ setOpenAccordions(prev => ({ ...prev, [groupId]: !prev[groupId] }));
218
+ };
219
+ const handleItemClick = (item, group) => {
220
+ if (onSelectedItemChange) {
221
+ onSelectedItemChange(item);
222
+ }
223
+ if (group.onItemClick) {
224
+ group.onItemClick(item);
225
+ }
226
+ };
227
+ const handleItemDoubleClick = (item, group) => {
228
+ if (group.onItemDoubleClick) {
229
+ group.onItemDoubleClick(item);
230
+ }
231
+ };
232
+ const handleContextMenu = (event, item, group) => {
233
+ event.preventDefault();
234
+ if (!group.contextMenuItems) {
235
+ return;
236
+ }
237
+ const menuItems = typeof group.contextMenuItems === 'function'
238
+ ? group.contextMenuItems(item)
239
+ : group.contextMenuItems;
240
+ if (menuItems.length === 0) {
241
+ return;
242
+ }
243
+ setAnchorEl(event.currentTarget);
244
+ setContextMenuItems(menuItems);
245
+ };
246
+ const closeContextMenu = useCallback(() => {
247
+ setAnchorEl(null);
248
+ }, []);
249
+ const handleHeaderContextMenu = (event, groupId) => {
250
+ event.preventDefault();
251
+ event.stopPropagation();
252
+ setHeaderContextPosition({ x: event.clientX, y: event.clientY });
253
+ setHeaderContextGroupId(groupId);
254
+ setHeaderContextVisible(true);
255
+ };
256
+ const handleHeaderClick = (event, groupId) => {
257
+ if (event.button !== 0)
258
+ return;
259
+ toggleAccordion(groupId);
260
+ };
261
+ const closeHeaderContextMenu = useCallback(() => {
262
+ setHeaderContextVisible(false);
263
+ setHeaderContextPosition(null);
264
+ setHeaderContextGroupId(null);
265
+ }, []);
266
+ const headerContextMenuItems = headerContextGroupId ? [
267
+ {
268
+ text: openAccordions[headerContextGroupId] ? 'Collassa' : 'Espandi',
269
+ onClick: () => {
270
+ toggleAccordion(headerContextGroupId);
271
+ closeHeaderContextMenu();
272
+ }
273
+ }
274
+ ] : [];
275
+ const getGroupColor = (group, index) => {
276
+ return group.color || DEFAULT_COLORS[index % DEFAULT_COLORS.length];
277
+ };
278
+ const renderBadges = (group, color) => {
279
+ if (group.badges && group.badges.length > 0) {
280
+ return (_jsx(BadgeContainer, { children: group.badges.map((badgeData, idx) => {
281
+ const badgeKey = `${group.id}-badge-${badgeData.badge}-${idx}`;
282
+ const badge = _jsx(Badge, { "$color": color, children: badgeData.badge });
283
+ if (badgeData.tooltip) {
284
+ return (_jsx(TMTooltip, { content: badgeData.tooltip, children: badge }, badgeKey));
285
+ }
286
+ return _jsx("span", { children: badge }, badgeKey);
287
+ }) }));
288
+ }
289
+ if (group.dataSource && group.dataSource.length > 0) {
290
+ return _jsx(Badge, { "$color": color, children: group.dataSource.length });
291
+ }
292
+ return null;
293
+ };
294
+ const renderAccordion = (group, index) => {
295
+ const color = getGroupColor(group, index);
296
+ const isOpen = openAccordions[group.id] ?? true;
297
+ if (group.customComponent) {
298
+ return (_jsxs(AccordionItem, { children: [_jsxs(AccordionHeader, { "$color": color, "$isOpen": isOpen, onClick: (e) => handleHeaderClick(e, group.id), onContextMenu: (e) => handleHeaderContextMenu(e, group.id), children: [_jsxs(AccordionTitle, { children: [group.icon, _jsx(TitleText, { children: group.title })] }), _jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: '10px' }, children: [renderBadges(group, color), _jsx(ToggleIcon, { "$isOpen": isOpen, children: _jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", children: _jsx("path", { d: "M4 6L8 10L12 6", stroke: "#495057", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }) })] })] }), isOpen && (_jsx(CustomComponentContainer, { children: group.customComponent }))] }, group.id));
299
+ }
300
+ if (!group.dataSource || group.dataSource.length === 0)
301
+ return null;
302
+ if (!group.renderItem) {
303
+ return (_jsxs(AccordionItem, { children: [_jsxs(AccordionHeader, { "$color": color, "$isOpen": isOpen, onClick: (e) => handleHeaderClick(e, group.id), onContextMenu: (e) => handleHeaderContextMenu(e, group.id), children: [_jsxs(AccordionTitle, { children: [group.icon, _jsx(TitleText, { children: group.title })] }), _jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: '10px' }, children: [renderBadges(group, color), _jsx(ToggleIcon, { "$isOpen": isOpen, children: _jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", children: _jsx("path", { d: "M4 6L8 10L12 6", stroke: "#495057", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }) })] })] }), _jsx(AccordionContent, { "$isOpen": isOpen, "$maxHeight": 100, children: _jsxs(ErrorMessage, { children: ["\u26A0\uFE0F renderItem function is required for \"", group.title, "\" group"] }) })] }, group.id));
304
+ }
305
+ const itemHeight = group.itemHeight || 80;
306
+ const maxHeight = group.dataSource.length * itemHeight + 20;
307
+ return (_jsxs(AccordionItem, { children: [_jsxs(AccordionHeader, { "$color": color, "$isOpen": isOpen, onClick: (e) => handleHeaderClick(e, group.id), onContextMenu: (e) => handleHeaderContextMenu(e, group.id), children: [_jsxs(AccordionTitle, { children: [group.icon, _jsx(TitleText, { children: group.title })] }), _jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: '10px' }, children: [renderBadges(group, color), _jsx(ToggleIcon, { "$isOpen": isOpen, children: _jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", children: _jsx("path", { d: "M4 6L8 10L12 6", stroke: "#495057", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }) })] })] }), _jsx(AccordionContent, { "$isOpen": isOpen, "$maxHeight": maxHeight, children: _jsx(ItemsList, { children: group.dataSource.map((item, itemIndex) => {
308
+ const isSelected = selectedItem === item;
309
+ const isFocused = focusedItem === item;
310
+ return (_jsx(ListItem, { "$isSelected": isSelected, "$color": color, onClick: () => handleItemClick(item, group), onDoubleClick: () => handleItemDoubleClick(item, group), onMouseEnter: () => setFocusedItem(item), onMouseLeave: () => setFocusedItem(undefined), onContextMenu: (e) => handleContextMenu(e, item, group), children: group.renderItem(item, isSelected, isFocused, color) }, itemIndex * 2));
311
+ }) }) })] }, group.id));
312
+ };
313
+ if (!isInitialized) {
314
+ return (_jsx(LoadingContainer, { children: _jsx(LoadIndicator, { height: 40, width: 40 }) }));
315
+ }
316
+ if (!groups || groups.length === 0) {
317
+ return (_jsx(Container, { children: _jsx(ErrorMessage, { children: "\u26A0\uFE0F No accordion groups defined" }) }));
318
+ }
319
+ const handleContainerContextMenu = (event) => {
320
+ if (event.target === event.currentTarget) {
321
+ event.preventDefault();
322
+ }
323
+ };
324
+ return (_jsxs(_Fragment, { children: [_jsx(Container, { onContextMenu: handleContainerContextMenu, children: groups.map((group, index) => renderAccordion(group, index)) }), anchorEl && contextMenuItems.length > 0 && (_jsx(ContextMenu, { dataSource: contextMenuItems, target: anchorEl, onHiding: closeContextMenu })), headerContextPosition && headerContextMenuItems.length > 0 && (_jsx(ContextMenu, { dataSource: headerContextMenuItems, visible: headerContextVisible, position: { my: 'left top', at: 'left top', offset: `${headerContextPosition.x} ${headerContextPosition.y}` }, onHiding: closeHeaderContextMenu }))] }));
325
+ };
326
+ export default TMAccordion;
@@ -16,6 +16,7 @@ export interface ITMButton extends ITMEditorBase {
16
16
  padding?: string;
17
17
  showTooltip?: boolean;
18
18
  onClick?: VoidFunction;
19
+ onMouseDown?: (e: any) => any;
19
20
  }
20
21
  declare const TMButton: React.ForwardRefExoticComponent<ITMButton & React.RefAttributes<HTMLButtonElement>>;
21
22
  export default TMButton;
@@ -145,23 +145,23 @@ const StyledAdvancedButtonText = styled.div `
145
145
  padding: 5px;
146
146
  `;
147
147
  const TMButton = forwardRef((props, ref) => {
148
- const { width, height, keyGesture, btnStyle = 'normal', advancedColor, advancedType = 'primary', color = 'primary', fontSize = FontSize.defaultFontSize, disabled = false, showTooltip = true, caption, icon, description, padding, elementStyle, onClick = () => { } } = props;
148
+ const { width, height, keyGesture, btnStyle = 'normal', advancedColor, advancedType = 'primary', color = 'primary', fontSize = FontSize.defaultFontSize, disabled = false, showTooltip = true, caption, icon, description, padding, elementStyle, onClick = () => { }, onMouseDown = () => { } } = props;
149
149
  const [isHovered, setIsHovered] = useState(false);
150
150
  const renderedButton = () => {
151
151
  if (btnStyle === 'normal') {
152
- return (_jsx(StyledNormalButton, { ref: ref, width: width, height: height, color: color, caption: caption, disabled: disabled, fontSize: fontSize, onClick: onClick, children: caption }));
152
+ return (_jsx(StyledNormalButton, { ref: ref, width: width, height: height, color: color, caption: caption, disabled: disabled, fontSize: fontSize, onClick: onClick, onMouseDown: (e) => !disabled && onMouseDown?.(e), children: caption }));
153
153
  }
154
154
  else if (btnStyle === 'toolbar') {
155
- return (_jsx(StyledToolbarButton, { ref: ref, color: color, caption: caption, disabled: disabled, fontSize: fontSize, onClick: onClick, children: icon }));
155
+ return (_jsx(StyledToolbarButton, { ref: ref, color: color, caption: caption, disabled: disabled, fontSize: fontSize, onClick: onClick, onMouseDown: (e) => !disabled && onMouseDown?.(e), children: icon }));
156
156
  }
157
157
  else if (btnStyle === 'icon') {
158
- return (_jsx(StyledIconButton, { ref: ref, color: color, caption: caption, disabled: disabled, fontSize: fontSize, padding: padding, onClick: onClick, children: icon }));
158
+ return (_jsx(StyledIconButton, { ref: ref, color: color, caption: caption, disabled: disabled, fontSize: fontSize, padding: padding, onClick: onClick, onMouseDown: (e) => !disabled && onMouseDown?.(e), children: icon }));
159
159
  }
160
160
  else if (btnStyle === 'advanced') {
161
- return (_jsxs(StyledAdvancedButton, { ref: ref, "$width": width ?? '90px', "$height": height ?? '30px', onMouseOver: () => !disabled && setIsHovered(true), onMouseOut: () => setIsHovered(false), "$isDisabled": disabled, "$isPrimaryOutline": advancedType === 'primary' && (advancedColor === 'primaryOutline' || color === 'primaryOutline'), onClick: () => !disabled && onClick?.(), children: [_jsx(StyledAdvancedButtonIcon, { "$color": advancedColor, "$isVisible": isHovered, "$isDisabled": disabled, "$type": advancedType, children: icon }), _jsx(StyledAdvancedButtonText, { "$color": advancedColor, "$isDisabled": disabled, "$type": advancedType, children: caption })] }));
161
+ return (_jsxs(StyledAdvancedButton, { ref: ref, "$width": width ?? '90px', "$height": height ?? '30px', onMouseOver: () => !disabled && setIsHovered(true), onMouseOut: () => setIsHovered(false), "$isDisabled": disabled, "$isPrimaryOutline": advancedType === 'primary' && (advancedColor === 'primaryOutline' || color === 'primaryOutline'), onClick: () => !disabled && onClick?.(), onMouseDown: (e) => !disabled && onMouseDown?.(e), children: [_jsx(StyledAdvancedButtonIcon, { "$color": advancedColor, "$isVisible": isHovered, "$isDisabled": disabled, "$type": advancedType, children: icon }), _jsx(StyledAdvancedButtonText, { "$color": advancedColor, "$isDisabled": disabled, "$type": advancedType, children: caption })] }));
162
162
  }
163
163
  else {
164
- return (_jsx(StyledTextButton, { ref: ref, color: color, caption: caption, disabled: disabled, fontSize: fontSize, onClick: onClick, children: caption }));
164
+ return (_jsx(StyledTextButton, { ref: ref, color: color, caption: caption, disabled: disabled, fontSize: fontSize, onClick: onClick, onMouseDown: (e) => !disabled && onMouseDown?.(e), children: caption }));
165
165
  }
166
166
  };
167
167
  const renderTooltip = () => {
@@ -7,5 +7,5 @@ type TMCustomButtonProps = {
7
7
  selectedItems?: Array<any>;
8
8
  onClose?: () => void;
9
9
  };
10
- declare const TMCustomButton: (props: TMCustomButtonProps) => import("react/jsx-runtime").JSX.Element | null;
10
+ declare const TMCustomButton: (props: TMCustomButtonProps) => false | import("react/jsx-runtime").JSX.Element;
11
11
  export default TMCustomButton;
@@ -1,13 +1,14 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { SDK_Globals } from '@topconsultnpm/sdk-ts';
3
- import { useEffect, useRef, useState } from 'react';
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useEffect, useRef, useState, useMemo } from 'react';
4
3
  import TMModal from './TMModal';
5
4
  import styled from 'styled-components';
6
- import { processButtonAttributes } from '../../helper/dcmtsHelper';
5
+ import { SDKUI_Localizator, TMLayoutWaitingContainer } from '../..';
6
+ import { getButtonAttributes, getSelectedItem } from '../../helper/dcmtsHelper';
7
7
  const IframeContainer = styled.div `
8
8
  display: flex;
9
9
  height: 100%;
10
10
  flex-direction: column;
11
+ padding-left: 15px;
11
12
  `;
12
13
  const StyledIframe = styled.iframe `
13
14
  border: none;
@@ -17,47 +18,101 @@ const TMCustomButton = (props) => {
17
18
  const { button, isModal = true, formData, selectedItems, onClose } = props;
18
19
  const { appName: scriptUrl, arguments: args } = button;
19
20
  const iframeRef = useRef(null);
20
- const attributes = processButtonAttributes(args, formData);
21
+ const attributes = useMemo(() => getButtonAttributes(args, formData, selectedItems), [args, formData, selectedItems]);
22
+ const RunOnce = button.mode === "RunOnce";
21
23
  const [loading, setLoading] = useState(true);
22
24
  const [error, setError] = useState(false);
23
- const getTargetOrigin = (url) => {
24
- if (!url)
25
+ const selectedItemsCount = selectedItems?.length || 0;
26
+ // Stati per il wait panel
27
+ const [showWaitPanel, setShowWaitPanel] = useState(selectedItemsCount > 0 && !RunOnce);
28
+ const [waitPanelText, setWaitPanelText] = useState(SDKUI_Localizator.CustomButtonActions.replaceParams(1, selectedItemsCount));
29
+ const [waitPanelValue, setWaitPanelValue] = useState(0);
30
+ const [waitPanelMaxValue, setWaitPanelMaxValue] = useState(selectedItemsCount);
31
+ const [abortController, setAbortController] = useState(undefined);
32
+ const targetOrigin = useMemo(() => {
33
+ if (!scriptUrl)
25
34
  return '*';
26
35
  try {
27
- const urlObj = new URL(url);
36
+ const urlObj = new URL(scriptUrl);
28
37
  return urlObj.origin;
29
38
  }
30
39
  catch {
31
40
  return '*';
32
41
  }
33
- };
34
- useEffect(() => {
35
- if (iframeRef.current?.contentWindow) {
36
- const mergedAttributes = { ...attributes, selectedItems: selectedItems };
37
- iframeRef.current.contentWindow.postMessage({
38
- "options": mergedAttributes,
39
- "selectedItems": selectedItems,
40
- "session": SDK_Globals.tmSession
41
- }, getTargetOrigin(scriptUrl));
42
- }
43
- clearTimeout(timeoutIframe);
44
- }, [loading, error, scriptUrl, attributes]);
42
+ }, [scriptUrl]);
45
43
  const handleLoad = () => setLoading(false);
46
44
  const handleError = () => {
47
45
  setLoading(false);
48
46
  setError(true);
49
47
  };
50
- // Timeout di sicurezza nel caso l'evento 'error' non venga chiamato
51
- const timeoutIframe = setTimeout(() => {
52
- if (loading)
53
- handleError();
54
- }, 5000); // 5 secondi
48
+ const executeSequentially = async (controller) => {
49
+ if (!selectedItems)
50
+ return;
51
+ for (const [index, item] of selectedItems.entries()) {
52
+ if (controller.signal.aborted)
53
+ break;
54
+ setWaitPanelText(SDKUI_Localizator.CustomButtonActions.replaceParams(index + 1, selectedItemsCount));
55
+ setWaitPanelValue(index);
56
+ // Attendi che l'iframe sia pronto e invia il messaggio
57
+ await new Promise((resolve) => {
58
+ const checkIframe = setInterval(() => {
59
+ if (iframeRef.current?.contentWindow) {
60
+ clearInterval(checkIframe);
61
+ //devo convertire item in formData
62
+ const processedItem = getSelectedItem(args, formData, item);
63
+ postMessageIframe(processedItem);
64
+ // Attendi prima di passare al prossimo
65
+ setTimeout(() => {
66
+ setWaitPanelValue(index + 1);
67
+ resolve();
68
+ }, 500);
69
+ }
70
+ }, 100);
71
+ });
72
+ }
73
+ setShowWaitPanel(false);
74
+ onClose?.();
75
+ };
76
+ const postMessageIframe = (data) => {
77
+ console.log("TMCustomButton - postMessageIframe - data:", data);
78
+ if (iframeRef.current?.contentWindow) {
79
+ iframeRef.current.contentWindow.postMessage({ "options": data }, targetOrigin);
80
+ }
81
+ };
82
+ useEffect(() => {
83
+ if (loading || error)
84
+ return;
85
+ //if(error) clearTimeout(timeoutIframe);
86
+ if (!RunOnce && selectedItemsCount > 0) {
87
+ // esegui per ogni item selezionato
88
+ const controller = new AbortController();
89
+ controller.signal.addEventListener('abort', () => {
90
+ setShowWaitPanel(false);
91
+ onClose?.();
92
+ });
93
+ setAbortController(controller);
94
+ setWaitPanelMaxValue(selectedItemsCount);
95
+ executeSequentially(controller);
96
+ }
97
+ else {
98
+ // Modalità RunOnce: invia dati all'iframe quando è caricato
99
+ postMessageIframe(attributes);
100
+ if (!RunOnce) {
101
+ //chiudo l'iframe dopo 2 secondi
102
+ setTimeout(() => {
103
+ onClose?.();
104
+ }, 2000);
105
+ }
106
+ //clearTimeout(timeoutIframe);
107
+ }
108
+ }, [loading, error, RunOnce]);
55
109
  useEffect(() => {
56
- if (!isModal && scriptUrl) {
110
+ if (!isModal && RunOnce && scriptUrl) {
57
111
  window.open(scriptUrl, '_blank');
58
112
  onClose?.();
59
113
  }
60
- }, [isModal, scriptUrl, onClose]);
61
- return isModal ? (_jsx(TMModal, { title: button.title, width: '60%', height: '60%', resizable: true, onClose: onClose, children: _jsxs(IframeContainer, { children: [error && _jsx("div", { children: "Si \u00E8 verificato un errore nel caricamento del contenuto." }), !error && _jsx(StyledIframe, { ref: iframeRef, loading: 'lazy', onLoad: handleLoad, onError: handleError, src: scriptUrl })] }) })) : null;
114
+ }, []);
115
+ const iframeContent = (_jsxs(IframeContainer, { style: !RunOnce ? { visibility: 'hidden' } : {}, children: [error && _jsx("div", { children: "Si \u00E8 verificato un errore nel caricamento del contenuto." }), !error && _jsx(StyledIframe, { ref: iframeRef, loading: 'lazy', onLoad: handleLoad, onError: handleError, src: scriptUrl })] }));
116
+ return isModal && RunOnce ? (_jsx(TMModal, { title: button.title, width: '60%', height: '70%', resizable: true, expandable: true, onClose: onClose, children: iframeContent })) : !RunOnce && (_jsxs(_Fragment, { children: [_jsx(TMLayoutWaitingContainer, { showWaitPanel: showWaitPanel, waitPanelTitle: SDKUI_Localizator.CustomButtonAction, showWaitPanelPrimary: true, waitPanelTextPrimary: waitPanelText, waitPanelValuePrimary: waitPanelValue, waitPanelMaxValuePrimary: waitPanelMaxValue, showWaitPanelSecondary: false, isCancelable: true, abortController: abortController, children: undefined }), iframeContent] }));
62
117
  };
63
118
  export default TMCustomButton;
@@ -64,7 +64,7 @@ const TMDataGridExportForm = (props) => {
64
64
  // Retrieve columns from the search result, or use an empty array if not available
65
65
  const columns = searchResult?.dtdResult?.columns ?? [];
66
66
  // If exportDescriptionsForDataLists is true, build a map of values to labels for the columns; otherwise use an empty Map
67
- const { valueToNameMap, captions } = exportDescriptionsForDataLists ? await buildValueToLabelMapFromDataColumns(columns) : { valueToNameMap: new Map(), captions: new Set() };
67
+ const valueToNameMap = exportDescriptionsForDataLists ? await buildValueToLabelMapFromDataColumns(columns) : new Map();
68
68
  // Create a Set from selectedRowKeys for efficient lookup
69
69
  const selectedSet = new Set(selectedRowKeys);
70
70
  // If exporting only selected rows, filter the dataSource accordingly; otherwise use the full dataSource
@@ -82,8 +82,14 @@ const TMDataGridExportForm = (props) => {
82
82
  const getValue = (col, value) => {
83
83
  // Replace raw value with corresponding label from the map if applicable
84
84
  let result = value;
85
- if (exportDescriptionsForDataLists && col.caption && captions.has(col.caption.toString())) {
86
- result = valueToNameMap.get(value) ?? value;
85
+ if (exportDescriptionsForDataLists && col.dataField && valueToNameMap.size > 0) {
86
+ const mapForField = valueToNameMap.get(col.dataField);
87
+ if (mapForField) {
88
+ result = mapForField.get(value) ?? value;
89
+ }
90
+ else {
91
+ result = value;
92
+ }
87
93
  }
88
94
  // If the column is a datetime type, attempt to format it as a locale date string
89
95
  if (col.dataType === 'datetime' && result) {
@@ -13,6 +13,7 @@ import TMButton from "./TMButton";
13
13
  import { TMSearchBar } from "../sidebar/TMHeader";
14
14
  import TMFileManagerThumbnailsView from "./TMFileManagerThumbnailsView";
15
15
  import TMFileManagerDataGridView from "./TMFileManagerDataGridView";
16
+ import { UserListCacheService } from "@topconsultnpm/sdk-ts";
16
17
  const TMFileManager = (props) => {
17
18
  // Destructure props
18
19
  const {
@@ -44,6 +45,14 @@ const TMFileManager = (props) => {
44
45
  const [droppedFiles, setDroppedFiles] = useState([]);
45
46
  // State to track whether a file drag operation is in progress
46
47
  const [isDragging, setIsDragging] = useState(false);
48
+ const [allUsers, setAllUsers] = useState([]);
49
+ useEffect(() => {
50
+ const fetchAllUsers = async () => {
51
+ const users = await UserListCacheService.GetAllAsync();
52
+ setAllUsers(users ?? []);
53
+ };
54
+ fetchAllUsers();
55
+ }, []);
47
56
  // useEffect runs whenever `treeFs` changes
48
57
  useEffect(() => {
49
58
  // Initialize an empty array to hold tree view directory data
@@ -198,7 +207,7 @@ const TMFileManager = (props) => {
198
207
  width: "100%",
199
208
  height: "100%",
200
209
  ...(isMobile && { display: openDraftList ? 'block' : 'none', transition: "opacity 0.3s ease-in-out" }),
201
- }, children: [_jsxs(Toolbar, { style: { backgroundColor: '#f4f4f4', height: "40px", paddingLeft: "5px", paddingRight: '5px' }, children: [!showPanel && _jsx(ToolbarItem, { location: "before", children: _jsx(TMButton, { caption: isLeftPanelCollapsed ? SDKUI_Localizator.ShowLeftPanel : SDKUI_Localizator.HideLeftPanel, btnStyle: 'toolbar', color: 'primaryOutline', icon: isLeftPanelCollapsed ? _jsx(IconHide, {}) : _jsx(IconShow, {}), onClick: () => setIsLeftPanelCollapsed(prev => !prev) }) }), _jsx(ToolbarItem, { location: "before", children: _jsx(TMButton, { caption: viewMode === 'details' ? SDKUI_Localizator.PreviewView : SDKUI_Localizator.DetailsView, btnStyle: 'toolbar', color: 'primaryOutline', icon: viewMode === 'details' ? _jsx(IconDashboard, {}) : _jsx(IconList, {}), onClick: toggleViewMode }) }), _jsx(ToolbarItem, { location: "before", children: _jsx(TMSearchBar, { marginLeft: '0px', maxWidth: '200px', searchValue: searchText, onSearchValueChanged: (e) => handleSearchChange(e) }) })] }), _jsxs("div", { onDrop: handleDrop, onDragOver: handleDragOver, onDragLeave: handleDragLeave, style: {
210
+ }, children: [_jsxs(Toolbar, { style: { backgroundColor: '#f4f4f4', height: "40px", paddingLeft: "5px", paddingRight: '5px' }, children: [!showPanel && _jsx(ToolbarItem, { location: "before", children: _jsx(TMButton, { caption: isLeftPanelCollapsed ? SDKUI_Localizator.ShowLeftPanel : SDKUI_Localizator.HideLeftPanel, btnStyle: 'toolbar', color: 'primaryOutline', icon: isLeftPanelCollapsed ? _jsx(IconHide, {}) : _jsx(IconShow, {}), onClick: () => setIsLeftPanelCollapsed(prev => !prev) }) }), _jsx(ToolbarItem, { location: "before", children: _jsx(TMButton, { caption: viewMode === 'details' ? SDKUI_Localizator.CompactView : SDKUI_Localizator.DetailsView, btnStyle: 'toolbar', color: 'primaryOutline', icon: viewMode === 'details' ? _jsx(IconDashboard, {}) : _jsx(IconList, {}), onClick: toggleViewMode }) }), _jsx(ToolbarItem, { location: "before", children: _jsx(TMSearchBar, { marginLeft: '0px', maxWidth: '200px', searchValue: searchText, onSearchValueChanged: (e) => handleSearchChange(e) }) })] }), _jsxs("div", { onDrop: handleDrop, onDragOver: handleDragOver, onDragLeave: handleDragLeave, style: {
202
211
  width: "100%",
203
212
  height: "calc(100% - 40px)",
204
213
  position: "relative",
@@ -219,6 +228,6 @@ const TMFileManager = (props) => {
219
228
  pointerEvents: "none",
220
229
  backdropFilter: "blur(3px)",
221
230
  textShadow: "0 2px 4px rgba(0,0,0,0.5)"
222
- }, children: SDKUI_Localizator.DropFileToShare }), viewMode === 'thumbnails' && _jsx(TMFileManagerThumbnailsView, { items: filteredFileItems ?? [], focusedFile: focusedFile, handleFocusedFile: handleFocusedFile, selectedFiles: selectedFiles, handleSelectedFiles: handleSelectedFiles, fileContextMenuItems: fileContextMenuItems, searchText: searchText, userID: userID, draftThumbViewAnchor: draftThumbViewAnchor, setDraftThumbViewAnchor: setDraftThumbViewAnchor, onDoubleClickHandler: onDoubleClickHandler }), viewMode === 'details' && _jsx(TMFileManagerDataGridView, { items: filteredFileItems ?? [], focusedFile: focusedFile, handleFocusedFile: handleFocusedFile, selectedFiles: selectedFiles, handleSelectedFiles: handleSelectedFiles, fileContextMenuItems: fileContextMenuItems, searchText: searchText, userID: userID, onDoubleClickHandler: onDoubleClickHandler })] })] })] }) }) });
231
+ }, children: SDKUI_Localizator.DropFileToShare }), viewMode === 'thumbnails' && _jsx(TMFileManagerThumbnailsView, { items: filteredFileItems ?? [], allUsers: allUsers, focusedFile: focusedFile, handleFocusedFile: handleFocusedFile, selectedFiles: selectedFiles, handleSelectedFiles: handleSelectedFiles, fileContextMenuItems: fileContextMenuItems, searchText: searchText, userID: userID, draftThumbViewAnchor: draftThumbViewAnchor, setDraftThumbViewAnchor: setDraftThumbViewAnchor, onDoubleClickHandler: onDoubleClickHandler }), viewMode === 'details' && _jsx(TMFileManagerDataGridView, { items: filteredFileItems ?? [], allUsers: allUsers, focusedFile: focusedFile, handleFocusedFile: handleFocusedFile, selectedFiles: selectedFiles, handleSelectedFiles: handleSelectedFiles, fileContextMenuItems: fileContextMenuItems, searchText: searchText, userID: userID, onDoubleClickHandler: onDoubleClickHandler })] })] })] }) }) });
223
232
  };
224
233
  export default TMFileManager;
@@ -1,6 +1,8 @@
1
1
  import { FileItem, TMFileManagerContextMenuItem } from "./TMFileManagerUtils";
2
+ import { UserDescriptor } from "@topconsultnpm/sdk-ts";
2
3
  interface TMFileManagerDataGridViewProps {
3
4
  items: Array<FileItem>;
5
+ allUsers: Array<UserDescriptor>;
4
6
  focusedFile: FileItem | undefined;
5
7
  handleFocusedFile: (fileItem: FileItem | undefined) => void;
6
8
  selectedFiles: Array<FileItem>;