@topconsultnpm/sdkui-react 6.19.0-dev1.36 → 6.19.0-dev1.37

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.
@@ -1,4 +1,5 @@
1
1
  import { ValidationItem } from '@topconsultnpm/sdk-ts';
2
+ export declare const sanitizeAndFormatComment: (raw?: string) => string;
2
3
  export interface ITMHtmlEditor {
3
4
  /** Width of the editor (e.g., '100%', '500px') */
4
5
  width?: string;
@@ -28,6 +29,10 @@ export interface ITMHtmlEditor {
28
29
  toolbarMode?: 'compact' | 'expanded';
29
30
  /** If true, the editor will be focused on mount */
30
31
  autoFocus?: boolean;
32
+ /** Maximum number of characters allowed in the editor */
33
+ maxLength?: number;
34
+ /** If true, displays a character count below the editor */
35
+ showCount?: boolean;
31
36
  }
32
37
  declare const TMHtmlEditor: (props: ITMHtmlEditor) => import("react/jsx-runtime").JSX.Element;
33
38
  export default TMHtmlEditor;
@@ -4,8 +4,33 @@ import HtmlEditor, { Toolbar, Item } from 'devextreme-react/html-editor';
4
4
  import ReactDOM from 'react-dom';
5
5
  import { SDKUI_Localizator } from '../../helper';
6
6
  import TMVilViewer from '../base/TMVilViewer';
7
+ import { TMMessageBoxManager, ButtonNames } from '../base/TMPopUp';
8
+ import TMTooltip from '../base/TMTooltip';
9
+ import { useDeviceType, DeviceType } from '../base/TMDeviceProvider';
10
+ export const sanitizeAndFormatComment = (raw = "") => {
11
+ if (!raw)
12
+ return "";
13
+ let cleanComment = raw
14
+ // Replace </p> with '' only if followed by <ol> or <ul>
15
+ .replace(/<\/p>(?=\s*<(ol|ul)>)/gi, '')
16
+ // Replace all other </p> with '\r\n'
17
+ .replace(/<\/p>/gi, '\r\n')
18
+ // Remove all <p> tags
19
+ .replace(/<p>/gi, '')
20
+ // Remove all <br> tags
21
+ .replace(/<br>/gi, '')
22
+ // Trim whitespace
23
+ .trim();
24
+ // Remove dangerous HTML elements
25
+ cleanComment = cleanComment.replace(/<(script|iframe|embed|object|link|style|img|video|audio|svg|form|input|button|textarea|select|pre|function)[^>]*>/gi, '');
26
+ return cleanComment;
27
+ };
7
28
  const TMHtmlEditor = (props) => {
8
- const { width = "100%", height = "100%", initialMarkup = "", mentionsConfig, onValueChanged, validationItems = [], isEditorEnabled: isEditorEnabledProp = false, toolbarMode = 'compact', autoFocus = false } = props;
29
+ const { width = "100%", height = "100%", initialMarkup = "", mentionsConfig, onValueChanged, validationItems = [], isEditorEnabled: isEditorEnabledProp = false, toolbarMode = 'compact', autoFocus = false, maxLength = 1000, showCount = true, } = props;
30
+ // Get the current device type (e.g., mobile, tablet, desktop) using a custom hook.
31
+ const deviceType = useDeviceType();
32
+ // This avoids unnecessary re-renders by only recalculating when deviceType changes.
33
+ let isMobile = useMemo(() => { return deviceType === DeviceType.MOBILE; }, [deviceType]);
9
34
  // Ref for HtmlEditor instance
10
35
  const editorRef = useRef(null);
11
36
  // State for editor enable/disable
@@ -14,13 +39,15 @@ const TMHtmlEditor = (props) => {
14
39
  const [markup, setMarkup] = useState(initialMarkup);
15
40
  // State to track the position (x, y coordinates) where the custom context menu should be displayed.
16
41
  const [contextMenuPos, setContextMenuPos] = useState(null);
17
- // State to indicate whether a paste operation is currently in progress
18
- const [isPasting, setIsPasting] = useState(false);
42
+ // State to track remaining characters
43
+ const [charactersRemaining, setCharactersRemaining] = useState(maxLength - initialMarkup.length);
44
+ useEffect(() => {
45
+ const cleanedMarkup = sanitizeAndFormatComment(markup);
46
+ setCharactersRemaining(maxLength - cleanedMarkup.length);
47
+ }, [markup, maxLength]);
19
48
  // Function to read text from the clipboard, format it, and paste into the Quill editor
20
49
  const pasteFromClipboard = async () => {
21
50
  try {
22
- // Set flag to indicate paste operation is in progress
23
- setIsPasting(true);
24
51
  // Read plain text from the clipboard asynchronously
25
52
  let text = await navigator.clipboard.readText();
26
53
  text = '<p>' + text.replace(/\r\n/g, '</p><p>') + '</p>';
@@ -52,10 +79,6 @@ const TMHtmlEditor = (props) => {
52
79
  // Log any errors that might occur during clipboard access or pasting
53
80
  console.warn('Clipboard paste failed:', err);
54
81
  }
55
- finally {
56
- // Reset paste state after a short delay to restore UI state
57
- setTimeout(() => setIsPasting(false), 500);
58
- }
59
82
  };
60
83
  useEffect(() => {
61
84
  const handleKeyDown = (e) => {
@@ -116,7 +139,7 @@ const TMHtmlEditor = (props) => {
116
139
  }, [autoFocus]);
117
140
  // Memoized check for validation errors
118
141
  const hasValidationErrors = useMemo(() => {
119
- return !isPasting && validationItems && validationItems.length > 0;
142
+ return validationItems && validationItems.length > 0;
120
143
  }, [validationItems]);
121
144
  // Handler function triggered by the context menu's "Paste" action
122
145
  const handlePaste = async () => {
@@ -125,9 +148,44 @@ const TMHtmlEditor = (props) => {
125
148
  // Close the custom context menu after pasting
126
149
  setContextMenuPos(null);
127
150
  };
128
- return (_jsxs("div", { style: { height: hasValidationErrors ? `calc(${height} - 30px)` : "100%", width: width }, onContextMenu: handleContextMenu, children: [_jsx("div", { className: "custom-mentions-wrapper", style: { borderWidth: '1px', borderStyle: 'solid', borderColor: hasValidationErrors ? "red" : "#e0e0e0 #e0e0e0 #616161", width: "100%", height: "100%" }, children: _jsx(HtmlEditor, { ref: editorRef, placeholder: SDKUI_Localizator.TypeAMessage + "...", width: "100%", height: "100%", value: markup, onValueChange: onValueChangeCallback, mentions: mentionsConfig, style: { overflow: 'hidden', outline: "none", fontSize: '1rem' }, children: isEditorEnabled && (toolbarMode === 'compact' ?
151
+ return (_jsxs("div", { style: {
152
+ height: height,
153
+ width: width
154
+ }, children: [_jsx("div", { className: "custom-mentions-wrapper", onContextMenu: handleContextMenu, style: {
155
+ borderWidth: '1px',
156
+ borderStyle: 'solid',
157
+ borderColor: hasValidationErrors ? "red" : "#e0e0e0 #e0e0e0 #616161",
158
+ width: "100%",
159
+ height: `calc(100% - ${showCount ? 15 : 0}px - ${validationItems.length > 0 ? 15 : 0}px)`,
160
+ }, children: _jsx(HtmlEditor, { ref: editorRef, placeholder: SDKUI_Localizator.TypeAMessage + "...", width: "100%", height: "100%", value: markup, onValueChange: onValueChangeCallback, mentions: mentionsConfig, style: { overflow: 'hidden', outline: "none", fontSize: '1rem' }, children: isEditorEnabled && (toolbarMode === 'compact' ?
129
161
  _jsxs(Toolbar, { multiline: false, children: [_jsx(Item, { name: "undo" }), _jsx(Item, { name: "redo" }), _jsx(Item, { name: "separator" }), _jsx(Item, { name: "bold" }), _jsx(Item, { name: "italic" }), _jsx(Item, { name: "strike" }), _jsx(Item, { name: "underline" }), _jsx(Item, { name: "separator" }), _jsx(Item, { name: "orderedList" }), _jsx(Item, { name: "bulletList" })] }) :
130
- _jsxs(Toolbar, { children: [_jsx(Item, { name: "undo" }), _jsx(Item, { name: "redo" }), _jsx(Item, { name: "separator" }), _jsx(Item, { name: "separator" }), _jsx(Item, { name: "bold" }), _jsx(Item, { name: "italic" }), _jsx(Item, { name: "strike" }), _jsx(Item, { name: "underline" }), _jsx(Item, { name: "separator" }), _jsx(Item, { name: "alignLeft" }), _jsx(Item, { name: "alignCenter" }), _jsx(Item, { name: "alignRight" }), _jsx(Item, { name: "alignJustify" }), _jsx(Item, { name: "separator" }), _jsx(Item, { name: "color" }), _jsx(Item, { name: "background" }), _jsx(Item, { name: "separator" }), _jsx(Item, { name: "link" }), _jsx(Item, { name: "image" }), _jsx(Item, { name: "separator" })] })) }) }), !isPasting && validationItems.length > 0 && (_jsx("div", { style: { width: "100%", height: "30px" }, children: _jsx(TMVilViewer, { vil: validationItems }) })), contextMenuPos &&
162
+ _jsxs(Toolbar, { children: [_jsx(Item, { name: "undo" }), _jsx(Item, { name: "redo" }), _jsx(Item, { name: "separator" }), _jsx(Item, { name: "separator" }), _jsx(Item, { name: "bold" }), _jsx(Item, { name: "italic" }), _jsx(Item, { name: "strike" }), _jsx(Item, { name: "underline" }), _jsx(Item, { name: "separator" }), _jsx(Item, { name: "alignLeft" }), _jsx(Item, { name: "alignCenter" }), _jsx(Item, { name: "alignRight" }), _jsx(Item, { name: "alignJustify" }), _jsx(Item, { name: "separator" }), _jsx(Item, { name: "color" }), _jsx(Item, { name: "background" }), _jsx(Item, { name: "separator" }), _jsx(Item, { name: "link" }), _jsx(Item, { name: "image" }), _jsx(Item, { name: "separator" })] })) }) }), showCount ? ((() => {
163
+ const cleanedMarkup = sanitizeAndFormatComment(markup);
164
+ const showInfoIcon = charactersRemaining !== maxLength;
165
+ return (_jsxs("div", { style: {
166
+ display: 'flex',
167
+ alignItems: 'center',
168
+ justifyContent: 'flex-end',
169
+ fontSize: 12,
170
+ color: '#6c757d',
171
+ marginTop: 4,
172
+ gap: 4,
173
+ }, children: [`${Math.max(charactersRemaining, 0)} ${SDKUI_Localizator.CharactersRemaining}`, showInfoIcon && (_jsx(TMTooltip, { content: 'Markup HTML', children: _jsx("span", { className: "dx-icon-codeblock", style: { fontSize: 22, cursor: 'pointer' }, onClick: () => {
174
+ TMMessageBoxManager.show({
175
+ title: 'Markup HTML',
176
+ initialWidth: !isMobile ? '700px' : undefined,
177
+ message: (_jsx("pre", { style: {
178
+ whiteSpace: 'pre-wrap',
179
+ background: '#f5f5f5',
180
+ padding: '12px',
181
+ borderRadius: '6px',
182
+ }, children: cleanedMarkup })),
183
+ resizable: true,
184
+ showToppy: false,
185
+ buttons: [ButtonNames.OK],
186
+ });
187
+ } }) }))] }));
188
+ })()) : null, validationItems.length > 0 && _jsx(TMVilViewer, { vil: validationItems }), contextMenuPos &&
131
189
  ReactDOM.createPortal(_jsxs("div", { style: {
132
190
  position: 'fixed',
133
191
  top: contextMenuPos.y,
@@ -10,7 +10,7 @@ import { TMExceptionBoxManager, TMMessageBoxManager, ButtonNames } from '../../b
10
10
  import TMSpinner from '../../base/TMSpinner';
11
11
  import TMTooltip from '../../base/TMTooltip';
12
12
  import TMUserAvatar from '../../base/TMUserAvatar';
13
- import TMHtmlEditor from '../../editors/TMHtmlEditor';
13
+ import TMHtmlEditor, { sanitizeAndFormatComment } from '../../editors/TMHtmlEditor';
14
14
  import TMChooserForm from '../../forms/TMChooserForm';
15
15
  import TMSaveForm from '../../forms/TMSaveForm';
16
16
  const getNonDirectoryFiles = (items, exclude) => {
@@ -28,6 +28,7 @@ const getNonDirectoryFiles = (items, exclude) => {
28
28
  });
29
29
  };
30
30
  const TMBlogCommentForm = (props) => {
31
+ const maxLength = 1000;
31
32
  const { participants, selectedAttachments, selectedAttachmentDid, allFileItems, allArchivedDocumentsFileItems = [], onClose, refreshCallback, context, showAttachmentsSection = true, updateShouldSelectLastBlog } = props;
32
33
  // Initialize state with combined array
33
34
  const [dataSource, setDataSource] = useState(() => [...getNonDirectoryFiles(allFileItems?.items || [], []), ...allArchivedDocumentsFileItems]);
@@ -39,20 +40,18 @@ const TMBlogCommentForm = (props) => {
39
40
  const validator = async (params) => {
40
41
  let vil = [];
41
42
  const { comment } = params;
43
+ const cleanedMarkup = sanitizeAndFormatComment(comment);
42
44
  // Check for empty comment
43
- if (!comment || comment.trim() === "") {
45
+ if (!cleanedMarkup || cleanedMarkup.trim() === "") {
44
46
  vil.push(new ValidationItem(ResultTypes.ERROR, SDKUI_Localizator.Comment, `${SDK_Localizator.RequiredField}`));
45
47
  }
46
48
  else {
47
- // Imposta la lunghezza massima consentita per il commento
48
- const maxLength = 1000;
49
49
  // Calcola la lunghezza effettiva del commento inserito
50
- const commentLength = comment.length;
51
- // Calcola di quanto la lunghezza del commento supera il limite massimo
52
- const exceededLength = commentLength - maxLength;
50
+ const commentLength = cleanedMarkup.length;
51
+ const exceededChars = commentLength - maxLength;
53
52
  // Validate description length (max 1000)
54
53
  if (commentLength > maxLength) {
55
- vil.push(new ValidationItem(ResultTypes.ERROR, SDKUI_Localizator.Comment, `${SDKUI_Localizator.DescriptionLengthExceededMessage.replaceParams(commentLength, maxLength, exceededLength)}`));
54
+ vil.push(new ValidationItem(ResultTypes.ERROR, SDKUI_Localizator.Comment, `${SDKUI_Localizator.DescriptionLengthExceededMessage.replaceParams(exceededChars)}`));
56
55
  }
57
56
  // Detect dangerous HTML tags
58
57
  const tagRegex = /<\/?(script|iframe|embed|object|link|style|img|video|audio|svg|form|input|button|textarea|select|pre|function)[^>]*>/gi;
@@ -115,19 +114,7 @@ const TMBlogCommentForm = (props) => {
115
114
  // Retrieve the comment from formData, or use an empty string if undefined
116
115
  const comment = formData?.comment ?? "";
117
116
  // Clean the comment by removing <p> tags and replacing </p> with line breaks
118
- let cleanComment = comment
119
- // Replace </p> with '' only if followed by <ol> or <ul>
120
- .replace(/<\/p>(?=\s*<(ol|ul)>)/gi, '')
121
- // Replace all other </p> with '\r\n'
122
- .replace(/<\/p>/gi, '\r\n')
123
- // Remove all <p> tags
124
- .replace(/<p>/gi, '')
125
- // Remove all <br> tags
126
- .replace(/<br>/gi, '')
127
- // Trim whitespace
128
- .trim();
129
- // Validate and remove any potentially dangerous HTML tags (like <script>, <iframe>, etc.)
130
- cleanComment = cleanComment.replace(/<(script|iframe|embed|object|link|style|img|video|audio|svg|form|input|button|textarea|select|pre|function)[^>]*>/gi, '');
117
+ const cleanComment = sanitizeAndFormatComment(comment);
131
118
  // Assign the cleaned comment as the description for the blog post
132
119
  blogPost.description = cleanComment ?? "";
133
120
  // If there are file items (attachments), process them
@@ -220,7 +207,7 @@ const TMBlogCommentForm = (props) => {
220
207
  // Update the state with selected draft items
221
208
  setCurrentDraftAttachments(selectedDraftItems);
222
209
  };
223
- return _jsx(TMSaveForm, { id: 1, title: SDKUI_Localizator.AddNewComment, showTitleFormMode: false, showErrorCount: false, customSaveButton: _jsx("i", { className: 'dx-icon-send' }), customTooltipSaveButton: SDKUI_Localizator.Send, showUndoButton: false, hasNavigation: false, skipIsModifiedCheck: true, isModal: true, width: calcResponsiveSizes(deviceType, '800px', '800px', '95%'), height: '550px', formMode: FormModes.Create, validationItems: validationItems, exception: exception, isModified: calcIsModified(formData, formDataOrig), onSaveAsync: onSaveAsync, onClose: onCloseCallback, customToolbarElements: _jsx("div", { style: { display: 'flex', gap: '2px' }, children: _jsx(TMButton, { btnStyle: "toolbar", icon: isEditorEnabled ? _jsx("i", { className: 'dx-icon-font' }) : _jsx("i", { className: 'dx-icon-background' }), caption: isEditorEnabled ? SDKUI_Localizator.HideFormattingOptions : SDKUI_Localizator.ShowFormattingOptions, onClick: toggleEditorMode }) }), children: _jsxs("div", { style: { width: "100%", height: "100%" }, children: [_jsxs("div", { style: { width: "100%", height: "100%" }, children: [_jsx("div", { style: { width: "100%", height: showAttachmentsSection ? "calc(100% - 60px)" : "100%" }, children: _jsx(TMHtmlEditor, { width: '100%', height: '100%', isEditorEnabled: isEditorEnabled, validationItems: validationItems, onValueChanged: onValueChanged, mentionsConfig: mentionsConfig, autoFocus: true }) }), showAttachmentsSection && _jsxs("div", { style: { display: 'flex', alignItems: 'center', height: '60px', marginTop: '10px' }, children: [_jsx("div", { style: {
210
+ return _jsx(TMSaveForm, { id: 1, title: SDKUI_Localizator.AddNewComment, showTitleFormMode: false, showErrorCount: false, customSaveButton: _jsx("i", { className: 'dx-icon-send' }), customTooltipSaveButton: SDKUI_Localizator.Send, showUndoButton: false, hasNavigation: false, skipIsModifiedCheck: true, isModal: true, width: calcResponsiveSizes(deviceType, '800px', '800px', '95%'), height: '550px', formMode: FormModes.Create, validationItems: validationItems, exception: exception, isModified: calcIsModified(formData, formDataOrig), onSaveAsync: onSaveAsync, onClose: onCloseCallback, customToolbarElements: _jsx("div", { style: { display: 'flex', gap: '2px' }, children: _jsx(TMButton, { btnStyle: "toolbar", icon: isEditorEnabled ? _jsx("i", { className: 'dx-icon-font' }) : _jsx("i", { className: 'dx-icon-background' }), caption: isEditorEnabled ? SDKUI_Localizator.HideFormattingOptions : SDKUI_Localizator.ShowFormattingOptions, onClick: toggleEditorMode }) }), children: _jsxs("div", { style: { width: "100%", height: "100%" }, children: [_jsxs("div", { style: { width: "100%", height: "100%" }, children: [_jsx("div", { style: { width: "100%", height: showAttachmentsSection ? "calc(100% - 60px)" : "100%" }, children: _jsx(TMHtmlEditor, { width: '100%', height: '100%', isEditorEnabled: isEditorEnabled, validationItems: validationItems, onValueChanged: onValueChanged, mentionsConfig: mentionsConfig, autoFocus: true, maxLength: maxLength }) }), showAttachmentsSection && _jsxs("div", { style: { display: 'flex', alignItems: 'center', height: '60px', marginTop: '10px' }, children: [_jsx("div", { style: {
224
211
  width: 'calc(100% - 60px)',
225
212
  overflowX: 'auto',
226
213
  whiteSpace: 'nowrap',
@@ -235,14 +222,22 @@ const TMBlogCommentForm = (props) => {
235
222
  const tooltipContent = (_jsxs("div", { style: { textAlign: 'left' }, children: [_jsxs("div", { children: [_jsxs("span", { style: { fontWeight: 'bold' }, children: [SDKUI_Localizator.Name, ":"] }), " ", draft.name ?? '-'] }), _jsxs("div", { children: [_jsxs("span", { style: { fontWeight: 'bold' }, children: [SDKUI_Localizator.Author, ":"] }), " ", draft.updaterName ?? '-'] }), _jsx("hr", {}), _jsxs("div", { children: [_jsxs("span", { style: { fontWeight: 'bold' }, children: [SDKUI_Localizator.Version, ":"] }), " ", draft.version] }), _jsxs("div", { children: [_jsxs("span", { style: { fontWeight: 'bold' }, children: [SDKUI_Localizator.Size, ":"] }), " ", formatBytes(draft.size ?? 0)] }), _jsx("hr", {}), _jsxs("div", { children: [_jsxs("span", { style: { fontWeight: 'bold' }, children: [SDKUI_Localizator.CreationTime, ":"] }), " ", Globalization.getDateTimeDisplayValue(draft.creationTime)] }), _jsxs("div", { children: [_jsxs("span", { style: { fontWeight: 'bold' }, children: [SDKUI_Localizator.LastUpdateTime, ":"] }), " ", Globalization.getDateTimeDisplayValue(draft.lastUpdateTime)] })] }));
236
223
  return _jsxs("div", { style: {
237
224
  display: 'inline-flex',
238
- alignItems: 'center',
239
- padding: '8px 12px',
240
- marginRight: '8px',
225
+ alignItems: 'center', // <-- this centers content vertically
226
+ padding: '4px 8px',
227
+ margin: '4px',
241
228
  border: '1px solid #ddd',
242
229
  borderRadius: '8px',
230
+ boxShadow: '0 2px 4px rgba(0, 0, 0, 0.1)',
231
+ cursor: 'pointer',
232
+ fontSize: '0.9rem',
243
233
  backgroundColor: '#fff',
244
- boxShadow: '0 2px 4px rgba(0,0,0,0.1)',
245
- }, children: [draft.ext ? (_jsx("span", { style: { marginRight: '10px' }, children: getFileIcon(draft.ext, undefined, tooltipContent) })) : (_jsx(IconAttachment, { style: { marginRight: '5px' } })), _jsx("span", { style: { marginRight: '8px' }, children: draft.name }), draft.version && _jsx("span", { style: {
234
+ }, onMouseEnter: (e) => {
235
+ e.currentTarget.style.boxShadow = '0 4px 8px rgba(0, 0, 0, 0.15)';
236
+ e.currentTarget.style.backgroundColor = '#cfcfcf';
237
+ }, onMouseLeave: (e) => {
238
+ e.currentTarget.style.boxShadow = '0 2px 4px rgba(0, 0, 0, 0.1)';
239
+ e.currentTarget.style.backgroundColor = '#fff';
240
+ }, children: [draft.ext ? (_jsx("span", { style: { marginRight: '10px', display: 'flex', alignItems: 'center' }, children: getFileIcon(draft.ext, undefined, tooltipContent) })) : (_jsx(IconAttachment, { style: { marginRight: '5px' } })), _jsx("span", { style: { marginRight: '8px', display: 'flex', alignItems: 'center' }, children: draft.name }), draft.version && (_jsx("span", { style: {
246
241
  display: 'inline-flex',
247
242
  width: '20px',
248
243
  height: '20px',
@@ -254,7 +249,7 @@ const TMBlogCommentForm = (props) => {
254
249
  fontWeight: 'bold',
255
250
  marginRight: '8px',
256
251
  boxShadow: '1px 1px 2px #00000020',
257
- }, children: _jsx(TMTooltip, { content: SDKUI_Localizator.Version, children: draft.version }) }), _jsx(TMTooltip, { content: SDKUI_Localizator.RemoveAttachment, children: _jsx("span", { onClick: () => removeAttachment(draft), style: {
252
+ }, children: _jsx(TMTooltip, { content: SDKUI_Localizator.Version, children: draft.version }) })), _jsx(TMTooltip, { content: SDKUI_Localizator.RemoveAttachment, children: _jsx("span", { onClick: () => removeAttachment(draft), style: {
258
253
  display: 'inline-flex',
259
254
  width: '20px',
260
255
  height: '20px',
@@ -265,21 +260,36 @@ const TMBlogCommentForm = (props) => {
265
260
  borderRadius: '30px',
266
261
  cursor: 'pointer',
267
262
  boxShadow: '1px 1px 2px #00000020',
268
- }, children: _jsx("span", { style: { fontSize: "15px" }, children: "\u00D7" }) }) })] }, draft.did);
269
- })) : (_jsx("div", { style: { color: '#999', width: '100%', textAlign: 'center' }, children: SDKUI_Localizator.NoAttachments })) }), _jsx(TMTooltip, { content: SDKUI_Localizator.Attachments, children: _jsx("i", { className: "dx-icon-attach", style: {
270
- width: '50px',
271
- height: '50px',
272
- marginLeft: '10px',
273
- fontSize: '20px',
274
- cursor: 'pointer',
275
- border: '1px solid #ccc',
276
- borderRadius: '8px',
277
- backgroundColor: '#f9f9f9',
278
- display: 'flex',
279
- alignItems: 'center',
280
- justifyContent: 'center',
281
- transition: 'all 0.2s ease-in-out',
282
- }, onMouseOver: (e) => (e.currentTarget.style.backgroundColor = '#e6f7ff'), onMouseOut: (e) => (e.currentTarget.style.backgroundColor = '#f9f9f9'), onClick: () => setShowAttachmentsForm(true) }) })] })] }), showAttachmentsForm && _jsx(TMAttachmentsView, { dataSource: dataSource, selectedIDs: currentDraftAttachments.map(draft => draft.id), onChoose: onChoose, onClose: () => setShowAttachmentsForm(false) })] }) });
263
+ }, children: _jsx("span", { style: { fontSize: '15px' }, children: "\u00D7" }) }) })] }, draft.did);
264
+ })) : (_jsx("div", { style: { color: '#999', width: '100%', textAlign: 'center' }, children: SDKUI_Localizator.NoAttachments })) }), _jsx(TMTooltip, { content: SDKUI_Localizator.Attachments + ": " + currentDraftAttachments.length, children: _jsxs("div", { style: { position: 'relative', display: 'inline-block' }, children: [_jsx("i", { className: "dx-icon-attach", style: {
265
+ width: '50px',
266
+ height: '50px',
267
+ marginLeft: '10px',
268
+ fontSize: '20px',
269
+ cursor: 'pointer',
270
+ border: '1px solid #ccc',
271
+ borderRadius: '8px',
272
+ backgroundColor: '#f9f9f9',
273
+ display: 'flex',
274
+ alignItems: 'center',
275
+ justifyContent: 'center',
276
+ transition: 'all 0.2s ease-in-out',
277
+ }, onMouseOver: (e) => (e.currentTarget.style.backgroundColor = '#e6f7ff'), onMouseOut: (e) => (e.currentTarget.style.backgroundColor = '#f9f9f9'), onClick: () => setShowAttachmentsForm(true) }), currentDraftAttachments.length > 0 && (_jsx("span", { style: {
278
+ position: 'absolute',
279
+ top: '-5px',
280
+ right: '-5px',
281
+ backgroundColor: '#203E5A',
282
+ color: 'white',
283
+ borderRadius: '50%',
284
+ minWidth: '20px',
285
+ height: '20px',
286
+ display: 'flex',
287
+ alignItems: 'center',
288
+ justifyContent: 'center',
289
+ padding: '0 6px',
290
+ fontSize: '12px',
291
+ fontWeight: 'bold',
292
+ }, children: currentDraftAttachments.length > 99 ? '99+' : currentDraftAttachments.length }))] }) })] })] }), showAttachmentsForm && _jsx(TMAttachmentsView, { dataSource: dataSource, selectedIDs: currentDraftAttachments.map(draft => draft.id), onChoose: onChoose, onClose: () => setShowAttachmentsForm(false) })] }) });
283
293
  };
284
294
  export default TMBlogCommentForm;
285
295
  const TMAttachmentsView = (props) => {
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import React, { useCallback, useEffect, useMemo, useState } from 'react';
3
- import { SDK_Globals, DataColumnTypes, MetadataDataDomains, DataListViewModes, MetadataFormats, LayoutModes, TemplateTIDs, DcmtTypeListCacheService, AccessLevels, SystemMIDsAsNumber } from '@topconsultnpm/sdk-ts';
3
+ import { SDK_Globals, DataColumnTypes, MetadataDataDomains, DataListViewModes, MetadataFormats, LayoutModes, TemplateTIDs, DcmtTypeListCacheService, AccessLevels, SystemMIDsAsNumber, RetrieveFileOptions, DcmtOpers, GeneralRetrieveFormats } from '@topconsultnpm/sdk-ts';
4
4
  import styled from 'styled-components';
5
5
  import { getCommandsMenuItems, getSelectedDcmtsOrFocused } from './TMSearchResultsMenuItems';
6
6
  import { genUniqueId, IconShow, IconBoard, IconDcmtTypeSys, IconDetailDcmts, SDKUI_Localizator, IconDelete, IconRefresh, IconMenuVertical, IconDownload, deepCompare, getDataColumnName, searchResultDescriptorToSimpleArray, searchResultToMetadataValues, IconSearchCheck, TMCommandsContextMenu } from '../../../helper';
@@ -153,15 +153,20 @@ const TMSearchResult = ({ context = SearchResultContext.METADATA_SEARCH, isVisib
153
153
  const openSharedArchiveHandler = async () => {
154
154
  const dcmts = getSelectedDcmtsOrFocused(selectedItems, focusedItem);
155
155
  if (dcmts.length === 0) {
156
- ShowAlert({ message: "Nessun documento selezionato", mode: "warning", duration: 3000 });
156
+ ShowAlert({ message: "Nessun documento selezionato", mode: "warning", title: 'Archivio Condivisa', duration: 3000 });
157
157
  return;
158
158
  }
159
- let dcmtFile = await getDcmtFileAsync(focusedItem.TID, focusedItem.DID, 'Archiviazione Condivisa', true);
160
- if (dcmtFile) {
161
- setSharedDcmtFile(dcmtFile?.file);
159
+ try {
160
+ const rfo = new RetrieveFileOptions();
161
+ rfo.retrieveReason = DcmtOpers.None;
162
+ rfo.generalRetrieveFormat = GeneralRetrieveFormats.OriginalUnsigned;
163
+ let dcmtFile = await getDcmtFileAsync({ TID: focusedItem?.TID, DID: focusedItem?.DID }, rfo, 'Archiviazione Condivisa', false, true);
164
+ if (dcmtFile) {
165
+ setSharedDcmtFile(dcmtFile?.file);
166
+ }
162
167
  }
163
- else {
164
- ShowAlert({ message: "Il documento selezionato non ha un file associato per l'archiviazione condivisa.", mode: "error", duration: 5000 });
168
+ catch (error) {
169
+ ShowAlert({ message: 'Il Documenti ha solo i metadati', mode: "warning", title: 'Archivio Condivisa', duration: 5000 });
165
170
  }
166
171
  setIsOpenSharedArchive(true);
167
172
  };
@@ -132,7 +132,7 @@ export declare class SDKUI_Localizator {
132
132
  static get DeletionOperationInterrupted(): "Löschvorgang abgebrochen" | "Deletion operation interrupted" | "Operación de eliminación interrumpida" | "Opération de suppression interrompue" | "Operação de exclusão interrompida" | "Operazione di eliminazione interrotta";
133
133
  static get Deny(): "Ablehnen" | "Deny" | "Denegar" | "Refuser" | "Negar" | "Negato";
134
134
  static get Description(): "Beschreibung" | "Description" | "Descripción" | "Descrição" | "Descrizione";
135
- static get DescriptionLengthExceededMessage(): "Die Beschreibung ist zu lang: {{0}}/{{1}} Zeichen ({{2}} zu viel)" | "Description is too long: {{0}}/{{1}} characters ({{2}} too many)" | "La descripción es demasiado larga: {{0}}/{{1}} caracteres ({{2}} de más)" | "La description est trop longue : {{0}}/{{1}} caractères ({{2}} en trop)" | "A descrição é demasiado longa: {{0}}/{{1}} caracteres ({{2}} a mais)" | "La descrizione è troppo lunga: {{0}}/{{1}} caratteri ({{2}} in più)";
135
+ static get DescriptionLengthExceededMessage(): "Die Beschreibung ist zu lang: {{0}} Zeichen zu viel" | "Description is too long: {{0}} characters too many" | "La descripción es demasiado larga: {{0}} caracteres de más" | "La description est trop longue : {{0}} caractères en trop" | "A descrição é demasiado longa: {{0}} caracteres a mais" | "La descrizione è troppo lunga: {{0}} caratteri in più";
136
136
  static get DescriptionTooLongMessage(): "Die Beschreibung ist zu lang: Maximal {{0}' Zeichen" | "Description is too long: Max {{0}} characters" | "La descripción es demasiado larga: Máximo {{0}} caracteres" | "La description est trop longue : Maximum {{0}} caractères" | "A descrição é demasiado longa: Máximo {{0}} caracteres" | "La descrizione è troppo lunga: Massimo {{0}} caratteri";
137
137
  static get Design(): "Design" | "Diseño" | "Conception" | "Projeto" | "Progettazione";
138
138
  static get Destination(): "Bestimmung" | "Destination" | "Destino" | "Destinazione";
@@ -1278,17 +1278,17 @@ export class SDKUI_Localizator {
1278
1278
  static get DescriptionLengthExceededMessage() {
1279
1279
  switch (this._cultureID) {
1280
1280
  case CultureIDs.De_DE:
1281
- return "Die Beschreibung ist zu lang: {{0}}/{{1}} Zeichen ({{2}} zu viel)";
1281
+ return "Die Beschreibung ist zu lang: {{0}} Zeichen zu viel";
1282
1282
  case CultureIDs.En_US:
1283
- return "Description is too long: {{0}}/{{1}} characters ({{2}} too many)";
1283
+ return "Description is too long: {{0}} characters too many";
1284
1284
  case CultureIDs.Es_ES:
1285
- return "La descripción es demasiado larga: {{0}}/{{1}} caracteres ({{2}} de más)";
1285
+ return "La descripción es demasiado larga: {{0}} caracteres de más";
1286
1286
  case CultureIDs.Fr_FR:
1287
- return "La description est trop longue : {{0}}/{{1}} caractères ({{2}} en trop)";
1287
+ return "La description est trop longue : {{0}} caractères en trop";
1288
1288
  case CultureIDs.Pt_PT:
1289
- return "A descrição é demasiado longa: {{0}}/{{1}} caracteres ({{2}} a mais)";
1289
+ return "A descrição é demasiado longa: {{0}} caracteres a mais";
1290
1290
  default:
1291
- return "La descrizione è troppo lunga: {{0}}/{{1}} caratteri ({{2}} in più)";
1291
+ return "La descrizione è troppo lunga: {{0}} caratteri in più";
1292
1292
  }
1293
1293
  }
1294
1294
  static get DescriptionTooLongMessage() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@topconsultnpm/sdkui-react",
3
- "version": "6.19.0-dev1.36",
3
+ "version": "6.19.0-dev1.37",
4
4
  "description": "",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\" && exit 1",