@topconsultnpm/sdkui-react 6.19.0-dev2.3 → 6.19.0-dev2.30

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 (100) hide show
  1. package/lib/components/NewComponents/ContextMenu/TMContextMenu.d.ts +4 -0
  2. package/lib/components/NewComponents/ContextMenu/TMContextMenu.js +187 -0
  3. package/lib/components/NewComponents/ContextMenu/hooks.d.ts +11 -0
  4. package/lib/components/NewComponents/ContextMenu/hooks.js +48 -0
  5. package/lib/components/NewComponents/ContextMenu/index.d.ts +2 -0
  6. package/lib/components/NewComponents/ContextMenu/index.js +1 -0
  7. package/lib/components/NewComponents/ContextMenu/styles.d.ts +27 -0
  8. package/lib/components/NewComponents/ContextMenu/styles.js +308 -0
  9. package/lib/components/NewComponents/ContextMenu/types.d.ts +26 -0
  10. package/lib/components/NewComponents/ContextMenu/types.js +1 -0
  11. package/lib/components/NewComponents/FloatingMenuBar/TMFloatingMenuBar.d.ts +4 -0
  12. package/lib/components/NewComponents/FloatingMenuBar/TMFloatingMenuBar.js +370 -0
  13. package/lib/components/NewComponents/FloatingMenuBar/index.d.ts +2 -0
  14. package/lib/components/NewComponents/FloatingMenuBar/index.js +2 -0
  15. package/lib/components/NewComponents/FloatingMenuBar/styles.d.ts +38 -0
  16. package/lib/components/NewComponents/FloatingMenuBar/styles.js +267 -0
  17. package/lib/components/NewComponents/FloatingMenuBar/types.d.ts +30 -0
  18. package/lib/components/NewComponents/FloatingMenuBar/types.js +1 -0
  19. package/lib/components/NewComponents/Notification/Notification.d.ts +4 -0
  20. package/lib/components/NewComponents/Notification/Notification.js +60 -0
  21. package/lib/components/NewComponents/Notification/NotificationContainer.d.ts +8 -0
  22. package/lib/components/NewComponents/Notification/NotificationContainer.js +33 -0
  23. package/lib/components/NewComponents/Notification/index.d.ts +2 -0
  24. package/lib/components/NewComponents/Notification/index.js +2 -0
  25. package/lib/components/NewComponents/Notification/styles.d.ts +21 -0
  26. package/lib/components/NewComponents/Notification/styles.js +180 -0
  27. package/lib/components/NewComponents/Notification/types.d.ts +18 -0
  28. package/lib/components/NewComponents/Notification/types.js +1 -0
  29. package/lib/components/base/TMCustomButton.js +79 -26
  30. package/lib/components/base/TMDataGridExportForm.d.ts +1 -1
  31. package/lib/components/base/TMDataGridExportForm.js +9 -3
  32. package/lib/components/base/TMFileManager.js +12 -3
  33. package/lib/components/base/TMFileManagerDataGridView.d.ts +2 -0
  34. package/lib/components/base/TMFileManagerDataGridView.js +11 -2
  35. package/lib/components/base/TMFileManagerThumbnailItems.d.ts +2 -0
  36. package/lib/components/base/TMFileManagerThumbnailItems.js +12 -2
  37. package/lib/components/base/TMFileManagerThumbnailsView.d.ts +2 -0
  38. package/lib/components/base/TMFileManagerThumbnailsView.js +2 -2
  39. package/lib/components/base/TMTooltip.d.ts +1 -1
  40. package/lib/components/base/TMTooltip.js +1 -1
  41. package/lib/components/choosers/TMDcmtTypeChooser.js +2 -2
  42. package/lib/components/choosers/TMMetadataChooser.d.ts +4 -1
  43. package/lib/components/choosers/TMMetadataChooser.js +28 -7
  44. package/lib/components/editors/TMDateBox.d.ts +1 -1
  45. package/lib/components/features/documents/TMDcmtForm.js +312 -56
  46. package/lib/components/features/documents/TMRelationViewer.js +56 -23
  47. package/lib/components/features/search/TMSavedQuerySelector.js +1 -1
  48. package/lib/components/features/search/TMSearch.js +2 -2
  49. package/lib/components/features/search/TMSearchQueryEditor.js +1 -1
  50. package/lib/components/features/search/TMSearchQueryPanel.js +8 -25
  51. package/lib/components/features/search/TMSearchResult.js +91 -10
  52. package/lib/components/features/search/TMSearchResultsMenuItems.d.ts +2 -1
  53. package/lib/components/features/search/TMSearchResultsMenuItems.js +97 -51
  54. package/lib/components/features/tasks/TMTaskForm.js +5 -4
  55. package/lib/components/features/tasks/TMTasksAgenda.js +4 -4
  56. package/lib/components/features/tasks/TMTasksCalendar.js +2 -2
  57. package/lib/components/features/tasks/TMTasksHeader.js +1 -1
  58. package/lib/components/features/tasks/TMTasksUtils.d.ts +2 -1
  59. package/lib/components/features/tasks/TMTasksUtils.js +18 -3
  60. package/lib/components/features/tasks/TMTasksUtilsView.js +26 -4
  61. package/lib/components/features/tasks/TMTasksView.js +12 -6
  62. package/lib/components/features/workflow/TMWorkflowPopup.js +3 -3
  63. package/lib/components/features/workflow/diagram/DiagramItemForm.js +11 -6
  64. package/lib/components/features/workflow/diagram/RecipientList.js +1 -1
  65. package/lib/components/forms/TMResultDialog.js +8 -2
  66. package/lib/components/grids/TMBlogsPost.d.ts +1 -0
  67. package/lib/components/grids/TMBlogsPost.js +20 -4
  68. package/lib/components/grids/TMBlogsPostUtils.js +5 -3
  69. package/lib/components/grids/TMRecentsManager.js +1 -1
  70. package/lib/components/layout/panelManager/TMPanelManagerContainer.d.ts +1 -0
  71. package/lib/components/layout/panelManager/TMPanelManagerContainer.js +2 -2
  72. package/lib/components/layout/panelManager/TMPanelManagerContext.js +0 -1
  73. package/lib/components/layout/panelManager/TMPanelManagerToolbar.js +2 -1
  74. package/lib/components/layout/panelManager/types.d.ts +1 -0
  75. package/lib/components/pages/TMPage.js +1 -1
  76. package/lib/components/query/TMQuerySummary.d.ts +1 -0
  77. package/lib/components/query/TMQuerySummary.js +3 -3
  78. package/lib/components/settings/SettingsAppearance.js +5 -5
  79. package/lib/components/viewers/TMDataListItemViewer.d.ts +1 -1
  80. package/lib/components/viewers/TMMidViewer.d.ts +1 -1
  81. package/lib/components/viewers/TMTidViewer.d.ts +1 -1
  82. package/lib/helper/GlobalStyles.d.ts +2 -0
  83. package/lib/helper/GlobalStyles.js +10 -0
  84. package/lib/helper/Globalization.d.ts +1 -0
  85. package/lib/helper/Globalization.js +30 -0
  86. package/lib/helper/SDKUI_Localizator.d.ts +34 -2
  87. package/lib/helper/SDKUI_Localizator.js +342 -22
  88. package/lib/helper/TMCustomSearchBar.js +1 -1
  89. package/lib/helper/TMIcons.d.ts +2 -1
  90. package/lib/helper/TMIcons.js +4 -1
  91. package/lib/helper/TMUtils.d.ts +1 -4
  92. package/lib/helper/TMUtils.js +18 -23
  93. package/lib/helper/dcmtsHelper.d.ts +2 -1
  94. package/lib/helper/dcmtsHelper.js +19 -13
  95. package/lib/helper/helpers.js +2 -1
  96. package/lib/helper/index.d.ts +1 -0
  97. package/lib/helper/index.js +1 -0
  98. package/lib/hooks/useRelatedDocuments.js +35 -26
  99. package/lib/ts/types.d.ts +1 -1
  100. package/package.json +8 -8
@@ -0,0 +1,30 @@
1
+ import type { TMContextMenuItemProps } from '../ContextMenu';
2
+ export interface TMFloatingMenuItem {
3
+ id: string;
4
+ name: string;
5
+ icon: React.ReactNode;
6
+ onClick: () => void;
7
+ disabled?: boolean;
8
+ isPinned?: boolean;
9
+ originalMenuItem?: TMContextMenuItemProps;
10
+ }
11
+ export interface TMFloatingMenuBarProps {
12
+ containerRef: React.RefObject<HTMLElement | null>;
13
+ contextMenuItems?: TMContextMenuItemProps[];
14
+ storageKey?: string;
15
+ isConstrained?: boolean;
16
+ defaultPosition?: Position;
17
+ maxItems?: number;
18
+ }
19
+ export interface Position {
20
+ x: number;
21
+ y: number;
22
+ }
23
+ export interface TMFloatingMenuBarState {
24
+ position: Position;
25
+ isDragging: boolean;
26
+ isConfigMode: boolean;
27
+ orientation: 'horizontal' | 'vertical';
28
+ items: TMFloatingMenuItem[];
29
+ draggedItemIndex: number | null;
30
+ }
@@ -0,0 +1,4 @@
1
+ import React from 'react';
2
+ import type { NotificationProps } from './types';
3
+ declare const Notification: React.FC<NotificationProps>;
4
+ export default Notification;
@@ -0,0 +1,60 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState, useEffect, useRef } from 'react';
3
+ import * as S from './styles';
4
+ const Notification = ({ title, message, mode = 'info', position = 'top-right', duration = 3000, closable = false, stopOnMouseEnter = true, hasProgress = true, onClose, }) => {
5
+ const [state, setState] = useState({
6
+ visible: true,
7
+ isPaused: false,
8
+ progress: 100,
9
+ });
10
+ const timeoutRef = useRef(undefined);
11
+ const remainingTimeRef = useRef(duration);
12
+ const pauseTimeRef = useRef(0);
13
+ const closeNotification = () => {
14
+ setState(prev => ({ ...prev, visible: false }));
15
+ setTimeout(() => {
16
+ onClose?.();
17
+ }, 300);
18
+ };
19
+ useEffect(() => {
20
+ // Set up auto-close timer
21
+ timeoutRef.current = setTimeout(() => {
22
+ closeNotification();
23
+ }, duration);
24
+ return () => {
25
+ if (timeoutRef.current) {
26
+ clearTimeout(timeoutRef.current);
27
+ }
28
+ };
29
+ }, [duration]);
30
+ const handleMouseEnter = () => {
31
+ if (!stopOnMouseEnter)
32
+ return;
33
+ // Pause the timer
34
+ if (timeoutRef.current) {
35
+ clearTimeout(timeoutRef.current);
36
+ pauseTimeRef.current = Date.now();
37
+ }
38
+ setState(prev => ({ ...prev, isPaused: true }));
39
+ };
40
+ const handleMouseLeave = () => {
41
+ if (!stopOnMouseEnter)
42
+ return;
43
+ // Resume the timer with remaining time
44
+ const pauseDuration = Date.now() - pauseTimeRef.current;
45
+ remainingTimeRef.current = Math.max(0, remainingTimeRef.current - pauseDuration);
46
+ timeoutRef.current = setTimeout(() => {
47
+ closeNotification();
48
+ }, remainingTimeRef.current);
49
+ setState(prev => ({ ...prev, isPaused: false }));
50
+ };
51
+ const handleClose = (e) => {
52
+ e.stopPropagation();
53
+ if (timeoutRef.current) {
54
+ clearTimeout(timeoutRef.current);
55
+ }
56
+ closeNotification();
57
+ };
58
+ return (_jsxs(S.NotificationContainer, { "$position": position, "$mode": mode, "$visible": state.visible, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, role: "alert", "aria-live": "assertive", children: [_jsxs(S.NotificationContent, { children: [_jsx(S.NotificationTitle, { children: title }), _jsx(S.NotificationMessage, { children: message })] }), closable && (_jsx(S.CloseButton, { onClick: handleClose, "aria-label": "Close notification", children: "\u00D7" })), hasProgress && (_jsx(S.ProgressBar, { "$duration": duration, "$mode": mode, "$isPaused": state.isPaused }))] }));
59
+ };
60
+ export default Notification;
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ import type { NotificationPosition } from './types';
3
+ interface NotificationContainerProps {
4
+ position: NotificationPosition;
5
+ children: React.ReactNode;
6
+ }
7
+ declare const NotificationContainer: React.FC<NotificationContainerProps>;
8
+ export default NotificationContainer;
@@ -0,0 +1,33 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import styled from 'styled-components';
3
+ const Container = styled.div `
4
+ position: fixed;
5
+ z-index: 10002;
6
+ display: flex;
7
+ flex-direction: column;
8
+ gap: 12px;
9
+ pointer-events: none;
10
+
11
+ ${props => {
12
+ const isTop = props.$position.startsWith('top');
13
+ const isBottom = props.$position.startsWith('bottom');
14
+ const isLeft = props.$position.endsWith('left');
15
+ const isRight = props.$position.endsWith('right');
16
+ const isCenter = props.$position.endsWith('center');
17
+ return `
18
+ ${isTop ? 'top: 24px;' : ''}
19
+ ${isBottom ? 'bottom: 24px;' : ''}
20
+ ${isLeft ? 'left: 24px;' : ''}
21
+ ${isRight ? 'right: 24px;' : ''}
22
+ ${isCenter ? 'left: 50%; transform: translateX(-50%);' : ''}
23
+ `;
24
+ }}
25
+
26
+ & > * {
27
+ pointer-events: auto;
28
+ }
29
+ `;
30
+ const NotificationContainer = ({ position, children }) => {
31
+ return _jsx(Container, { "$position": position, children: children });
32
+ };
33
+ export default NotificationContainer;
@@ -0,0 +1,2 @@
1
+ export { default } from './Notification';
2
+ export * from './types';
@@ -0,0 +1,2 @@
1
+ export { default } from './Notification';
2
+ export * from './types';
@@ -0,0 +1,21 @@
1
+ import type { NotificationMode, NotificationPosition } from './types';
2
+ export declare const NotificationContainer: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components/dist/types").Substitute<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {
3
+ $position: NotificationPosition;
4
+ $mode: NotificationMode;
5
+ $visible: boolean;
6
+ }>> & string;
7
+ export declare const NotificationContent: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
8
+ export declare const NotificationTitle: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
9
+ export declare const NotificationMessage: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
10
+ export declare const CloseButton: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, never>> & string;
11
+ export declare const ProgressBar: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components/dist/types").Substitute<import("styled-components/dist/types").Substitute<import("styled-components/dist/types").Substitute<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & {
12
+ ref?: ((instance: HTMLDivElement | null) => void | import("react").DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES[keyof import("react").DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES]) | import("react").RefObject<HTMLDivElement> | null | undefined;
13
+ }>, {
14
+ $duration: number;
15
+ $mode: NotificationMode;
16
+ $isPaused: boolean;
17
+ }>, {
18
+ $duration: number;
19
+ $mode: NotificationMode;
20
+ $isPaused: boolean;
21
+ }>> & string;
@@ -0,0 +1,180 @@
1
+ import styled, { keyframes } from 'styled-components';
2
+ const slideInFromTop = keyframes `
3
+ from {
4
+ opacity: 0;
5
+ transform: translateY(-100%);
6
+ }
7
+ to {
8
+ opacity: 1;
9
+ transform: translateY(0);
10
+ }
11
+ `;
12
+ const slideInFromBottom = keyframes `
13
+ from {
14
+ opacity: 0;
15
+ transform: translateY(100%);
16
+ }
17
+ to {
18
+ opacity: 1;
19
+ transform: translateY(0);
20
+ }
21
+ `;
22
+ const slideOut = keyframes `
23
+ from {
24
+ opacity: 1;
25
+ transform: scale(1);
26
+ }
27
+ to {
28
+ opacity: 0;
29
+ transform: scale(0.9);
30
+ }
31
+ `;
32
+ const getModeColors = (mode) => {
33
+ const colors = {
34
+ success: {
35
+ bg: '#10b981',
36
+ bgDark: '#059669',
37
+ border: '#34d399',
38
+ text: '#ffffff',
39
+ },
40
+ error: {
41
+ bg: '#ef4444',
42
+ bgDark: '#dc2626',
43
+ border: '#f87171',
44
+ text: '#ffffff',
45
+ },
46
+ warning: {
47
+ bg: '#f59e0b',
48
+ bgDark: '#d97706',
49
+ border: '#fbbf24',
50
+ text: '#ffffff',
51
+ },
52
+ info: {
53
+ bg: '#3b82f6',
54
+ bgDark: '#2563eb',
55
+ border: '#60a5fa',
56
+ text: '#ffffff',
57
+ },
58
+ };
59
+ return colors[mode];
60
+ };
61
+ export const NotificationContainer = styled.div `
62
+ position: relative;
63
+ z-index: 1;
64
+ min-width: 320px;
65
+ max-width: 420px;
66
+ background: ${props => getModeColors(props.$mode).bg};
67
+ border-radius: 12px;
68
+ box-shadow: 0 12px 40px rgba(0, 0, 0, 0.2),
69
+ 0 4px 12px rgba(0, 0, 0, 0.15);
70
+ padding: 16px 20px;
71
+ animation: ${props => {
72
+ if (!props.$visible)
73
+ return slideOut;
74
+ return props.$position.startsWith('top') ? slideInFromTop : slideInFromBottom;
75
+ }} 0.3s cubic-bezier(0.4, 0, 0.2, 1) forwards;
76
+ backdrop-filter: blur(10px);
77
+ border: 2px solid ${props => getModeColors(props.$mode).border};
78
+ color: ${props => getModeColors(props.$mode).text};
79
+ overflow: hidden;
80
+
81
+ [data-theme='dark'] & {
82
+ background: ${props => getModeColors(props.$mode).bgDark};
83
+ box-shadow: 0 12px 40px rgba(0, 0, 0, 0.4),
84
+ 0 4px 12px rgba(0, 0, 0, 0.3);
85
+ }
86
+
87
+ @media (max-width: 768px) {
88
+ min-width: 280px;
89
+ max-width: calc(100vw - 48px);
90
+ }
91
+ `;
92
+ export const NotificationContent = styled.div `
93
+ display: flex;
94
+ flex-direction: column;
95
+ gap: 6px;
96
+ padding-right: 24px;
97
+ `;
98
+ export const NotificationTitle = styled.div `
99
+ font-size: 16px;
100
+ font-weight: 600;
101
+ line-height: 1.4;
102
+ letter-spacing: -0.01em;
103
+ `;
104
+ export const NotificationMessage = styled.div `
105
+ font-size: 14px;
106
+ font-weight: 400;
107
+ line-height: 1.5;
108
+ opacity: 0.95;
109
+ `;
110
+ export const CloseButton = styled.button `
111
+ position: absolute;
112
+ top: 12px;
113
+ right: 12px;
114
+ background: transparent;
115
+ border: none;
116
+ color: inherit;
117
+ cursor: pointer;
118
+ width: 24px;
119
+ height: 24px;
120
+ display: flex;
121
+ align-items: center;
122
+ justify-content: center;
123
+ border-radius: 6px;
124
+ transition: all 0.15s ease;
125
+ font-size: 18px;
126
+ line-height: 1;
127
+ padding: 0;
128
+ opacity: 0.8;
129
+
130
+ &:hover {
131
+ opacity: 1;
132
+ background: rgba(255, 255, 255, 0.2);
133
+ transform: scale(1.1);
134
+ }
135
+
136
+ &:active {
137
+ transform: scale(0.95);
138
+ }
139
+
140
+ &:focus {
141
+ outline: 2px solid rgba(255, 255, 255, 0.5);
142
+ outline-offset: 2px;
143
+ }
144
+ `;
145
+ export const ProgressBar = styled.div.attrs(props => ({
146
+ style: {
147
+ animationDuration: `${props.$duration}ms`,
148
+ },
149
+ })) `
150
+ position: absolute;
151
+ bottom: 0;
152
+ left: 0;
153
+ height: 4px;
154
+ width: 100%;
155
+ background: ${props => getModeColors(props.$mode).border};
156
+ border-radius: 0 0 0 10px;
157
+ box-shadow: 0 0 8px ${props => getModeColors(props.$mode).border};
158
+ transform-origin: left;
159
+ animation: progress-shrink linear forwards;
160
+ animation-play-state: ${props => props.$isPaused ? 'paused' : 'running'};
161
+
162
+ @keyframes progress-shrink {
163
+ from {
164
+ transform: scaleX(1);
165
+ }
166
+ to {
167
+ transform: scaleX(0);
168
+ }
169
+ }
170
+
171
+ &::after {
172
+ content: '';
173
+ position: absolute;
174
+ top: 0;
175
+ right: 0;
176
+ width: 20px;
177
+ height: 100%;
178
+ background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.4));
179
+ }
180
+ `;
@@ -0,0 +1,18 @@
1
+ export type NotificationMode = 'warning' | 'info' | 'error' | 'success';
2
+ export type NotificationPosition = 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right';
3
+ export interface NotificationProps {
4
+ title: string;
5
+ message: string;
6
+ mode?: NotificationMode;
7
+ position?: NotificationPosition;
8
+ duration?: number;
9
+ closable?: boolean;
10
+ stopOnMouseEnter?: boolean;
11
+ hasProgress?: boolean;
12
+ onClose?: () => void;
13
+ }
14
+ export interface NotificationState {
15
+ visible: boolean;
16
+ isPaused: boolean;
17
+ progress: number;
18
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -1,13 +1,15 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { SDK_Globals } from '@topconsultnpm/sdk-ts';
3
- import { useEffect, useRef, useState } from 'react';
3
+ import { useEffect, useRef, useState, useMemo } from 'react';
4
4
  import TMModal from './TMModal';
5
5
  import styled from 'styled-components';
6
- import { processButtonAttributes } from '../../helper/dcmtsHelper';
6
+ import { TMLayoutWaitingContainer } from '../..';
7
+ import { processButtonAttributes, processSelectedItems } from '../../helper/dcmtsHelper';
7
8
  const IframeContainer = styled.div `
8
9
  display: flex;
9
10
  height: 100%;
10
11
  flex-direction: column;
12
+ padding-left: 15px;
11
13
  `;
12
14
  const StyledIframe = styled.iframe `
13
15
  border: none;
@@ -17,47 +19,98 @@ const TMCustomButton = (props) => {
17
19
  const { button, isModal = true, formData, selectedItems, onClose } = props;
18
20
  const { appName: scriptUrl, arguments: args } = button;
19
21
  const iframeRef = useRef(null);
20
- const attributes = processButtonAttributes(args, formData);
22
+ const attributes = useMemo(() => processButtonAttributes(args, formData), [args, formData]);
23
+ const selectedItemsProcessed = useMemo(() => processSelectedItems(selectedItems), [selectedItems]);
24
+ const RunOnce = button.mode === "RunOnce";
21
25
  const [loading, setLoading] = useState(true);
22
26
  const [error, setError] = useState(false);
23
- const getTargetOrigin = (url) => {
24
- if (!url)
27
+ const selectedItemsCount = selectedItems?.length || 1;
28
+ // Stati per il wait panel
29
+ const [showWaitPanel, setShowWaitPanel] = useState(true);
30
+ const [waitPanelText, setWaitPanelText] = useState("Esecuzione azione 1/" + selectedItemsCount.toString());
31
+ const [waitPanelValue, setWaitPanelValue] = useState(0);
32
+ const [waitPanelMaxValue, setWaitPanelMaxValue] = useState(selectedItemsCount);
33
+ const [abortController, setAbortController] = useState(undefined);
34
+ const targetOrigin = useMemo(() => {
35
+ if (!scriptUrl)
25
36
  return '*';
26
37
  try {
27
- const urlObj = new URL(url);
38
+ const urlObj = new URL(scriptUrl);
28
39
  return urlObj.origin;
29
40
  }
30
41
  catch {
31
42
  return '*';
32
43
  }
44
+ }, [scriptUrl]);
45
+ const handleLoad = () => setLoading(false);
46
+ const handleError = () => {
47
+ setLoading(false);
48
+ setError(true);
49
+ };
50
+ const executeSequentially = async (controller) => {
51
+ if (!selectedItemsProcessed)
52
+ return;
53
+ const processedItems = selectedItemsProcessed.length === 0 ? [...selectedItemsProcessed, attributes] : selectedItemsProcessed;
54
+ for (const [index, item] of processedItems.entries()) {
55
+ if (controller.signal.aborted)
56
+ break;
57
+ setWaitPanelText("Esecuzione azione " + (index + 1).toString() + "/" + selectedItemsCount.toString());
58
+ setWaitPanelValue(index);
59
+ // Attendi che l'iframe sia pronto e invia il messaggio
60
+ await new Promise((resolve) => {
61
+ const checkIframe = setInterval(() => {
62
+ if (iframeRef.current?.contentWindow) {
63
+ clearInterval(checkIframe);
64
+ iframeRef.current.contentWindow.postMessage({
65
+ "options": item,
66
+ "session": SDK_Globals.tmSession
67
+ }, targetOrigin);
68
+ // Attendi prima di passare al prossimo
69
+ setTimeout(() => {
70
+ setWaitPanelValue(index + 1);
71
+ resolve();
72
+ }, 500);
73
+ }
74
+ }, 100);
75
+ });
76
+ }
77
+ setShowWaitPanel(false);
78
+ onClose?.();
33
79
  };
34
80
  useEffect(() => {
35
- if (iframeRef.current?.contentWindow) {
36
- const mergedAttributes = { ...attributes, selectedItems: selectedItems };
81
+ if (loading || error)
82
+ return;
83
+ //if(error) clearTimeout(timeoutIframe);
84
+ console.log("TMCustomButton - useEffect - loading:", loading, " error:", error, " RunOnce:", RunOnce);
85
+ if (!RunOnce) {
86
+ // esegui per ogni item selezionato
87
+ const controller = new AbortController();
88
+ controller.signal.addEventListener('abort', () => {
89
+ setShowWaitPanel(false);
90
+ onClose?.();
91
+ });
92
+ setAbortController(controller);
93
+ setWaitPanelMaxValue(selectedItemsCount);
94
+ executeSequentially(controller);
95
+ }
96
+ else if (iframeRef.current?.contentWindow) {
97
+ // Modalità RunOnce: invia dati all'iframe quando è caricato
98
+ const mergedAttributes = { ...attributes, selectedItems: selectedItemsProcessed };
37
99
  iframeRef.current.contentWindow.postMessage({
38
100
  "options": mergedAttributes,
39
- "selectedItems": selectedItems,
40
101
  "session": SDK_Globals.tmSession
41
- }, getTargetOrigin(scriptUrl));
102
+ }, targetOrigin);
103
+ //clearTimeout(timeoutIframe);
42
104
  }
43
- clearTimeout(timeoutIframe);
44
- }, [loading, error, scriptUrl, attributes]);
45
- const handleLoad = () => setLoading(false);
46
- const handleError = () => {
47
- setLoading(false);
48
- setError(true);
49
- };
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
105
+ }, [loading, error, RunOnce]);
55
106
  useEffect(() => {
56
- if (!isModal && scriptUrl) {
107
+ if (!isModal && RunOnce && scriptUrl) {
57
108
  window.open(scriptUrl, '_blank');
58
109
  onClose?.();
59
110
  }
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;
111
+ }, []);
112
+ 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 })] }));
113
+ return isModal && RunOnce ? (_jsx(TMModal, { title: button.title, width: '60%', height: '70%', resizable: true, onClose: onClose, children: iframeContent })) : !RunOnce && showWaitPanel ? (_jsxs(_Fragment, { children: [_jsx(TMLayoutWaitingContainer, { showWaitPanel: true, waitPanelTitle: "Operazione in corso", showWaitPanelPrimary: true, waitPanelTextPrimary: waitPanelText, waitPanelValuePrimary: waitPanelValue, waitPanelMaxValuePrimary: waitPanelMaxValue, showWaitPanelSecondary: false, isCancelable: true, abortController: abortController, children: undefined }), iframeContent] }))
114
+ : null;
62
115
  };
63
116
  export default TMCustomButton;
@@ -1,4 +1,4 @@
1
- import { IColumnProps } from 'devextreme-react/cjs/data-grid';
1
+ import { IColumnProps } from 'devextreme-react/data-grid';
2
2
  import { SearchResultDescriptor } from '@topconsultnpm/sdk-ts';
3
3
  export type FormatOption = {
4
4
  value: 'csv' | 'xlsx' | 'xls' | 'txt';
@@ -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) {
@@ -8,11 +8,12 @@ import { TMColors } from "../../utils/theme";
8
8
  import TMPanel from "./TMPanel";
9
9
  import { TMSplitterLayout } from "./TMLayout";
10
10
  import { ContextMenu, TreeView } from "devextreme-react";
11
- import Toolbar, { Item as ToolbarItem } from 'devextreme-react/cjs/toolbar';
11
+ import Toolbar, { Item as ToolbarItem } from 'devextreme-react/toolbar';
12
12
  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>;