@topconsultnpm/sdkui-react 6.19.0-dev1.35 → 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.
- package/lib/components/editors/TMHtmlEditor.d.ts +5 -0
- package/lib/components/editors/TMHtmlEditor.js +70 -12
- package/lib/components/features/blog/TMBlogCommentForm.js +53 -43
- package/lib/components/features/search/TMSearchResult.js +18 -5
- package/lib/components/features/search/TMSearchResultsMenuItems.d.ts +1 -1
- package/lib/components/features/search/TMSearchResultsMenuItems.js +2 -2
- package/lib/helper/SDKUI_Localizator.d.ts +1 -1
- package/lib/helper/SDKUI_Localizator.js +6 -6
- package/lib/hooks/useRelatedDocuments.js +19 -11
- package/package.json +1 -1
|
@@ -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
|
|
18
|
-
const [
|
|
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
|
|
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: {
|
|
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" })] })) }) }),
|
|
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 (!
|
|
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 =
|
|
51
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
|
240
|
-
|
|
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
|
-
|
|
245
|
-
|
|
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:
|
|
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
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
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';
|
|
@@ -83,11 +83,12 @@ const TMSearchResult = ({ context = SearchResultContext.METADATA_SEARCH, isVisib
|
|
|
83
83
|
const [currentMetadataValues, setCurrentMetadataValues] = useState([]);
|
|
84
84
|
const [dcmtFormLayoutMode, setDcmtFormLayoutMode] = useState(LayoutModes.Update);
|
|
85
85
|
const [isModifiedBatchUpdate, setIsModifiedBatchUpdate] = useState(false);
|
|
86
|
+
const [sharedDcmtFile, setSharedDcmtFile] = useState(undefined);
|
|
86
87
|
// State to control whether the export form (for exporting to Excel/CSV/txt and others) should be shown
|
|
87
88
|
const [showExportForm, setShowExportForm] = useState(false);
|
|
88
89
|
const [confirmFormat, ConfirmFormatDialog] = useInputCvtFormatDialog();
|
|
89
90
|
const { openConfirmAttachmentsDialog, ConfirmAttachmentsDialog } = useInputAttachmentsDialog();
|
|
90
|
-
const { abortController, showWaitPanel, waitPanelTitle, showPrimary, waitPanelTextPrimary, waitPanelValuePrimary, waitPanelMaxValuePrimary, showSecondary, waitPanelTextSecondary, waitPanelValueSecondary, waitPanelMaxValueSecondary, downloadDcmtsAsync, runOperationAsync } = useDcmtOperations();
|
|
91
|
+
const { abortController, showWaitPanel, waitPanelTitle, showPrimary, waitPanelTextPrimary, waitPanelValuePrimary, waitPanelMaxValuePrimary, showSecondary, waitPanelTextSecondary, waitPanelValueSecondary, waitPanelMaxValueSecondary, downloadDcmtsAsync, runOperationAsync, getDcmtFileAsync } = useDcmtOperations();
|
|
91
92
|
const relatedDocuments = useRelatedDocuments({ selectedSearchResult, focusedItem, currentSearchResults });
|
|
92
93
|
const { relatedDcmts, showRelatedDcmtsChooser, archiveType, isOpenDetails, isOpenMaster, isOpenArchiveRelationForm, archiveRelatedDcmtFormTID, archiveRelatedDcmtFormMids, relatedDcmtsChooserDataSource, showPairDcmtsModal, isPairingManyToMany, pairedSearchResults, manyToManyRelations, selectedManyToManyRelation, showManyToManyChooser, manyToManyChooserDataSource, showPairSearchModal, pairSearchModalTargetTID, pairSearchModalParentTID, pairSearchModalParentDID, pairSearchModalRelation, pairSearchModalInputMids, currentTIDHasDetailRelations, currentTIDHasMasterRelations, canArchiveMasterRelation, canArchiveDetailRelation, hasManyToManyRelation, setIsOpenDetails, setIsOpenMaster, setShowRelatedDcmtsChooser, setShowManyToManyChooser, setShowPairDcmtsModal, setShowPairSearchModal, setIsOpenArchiveRelationForm, setArchiveType, setArchiveRelatedDcmtFormTID, setArchiveRelatedDcmtFormMids, pairFloatingActionConfig, pairSearchModalFloatingActionConfig, archiveMasterDocuments, archiveDetailDocuments, pairManyToMany, checkRelatedDcmtsArchiveCapability, checkManyToManyCapability, archiveRelatedDcmtHandler, executeManyToManyPairing, } = relatedDocuments;
|
|
93
94
|
const deviceType = useDeviceType();
|
|
@@ -149,12 +150,24 @@ const TMSearchResult = ({ context = SearchResultContext.METADATA_SEARCH, isVisib
|
|
|
149
150
|
});
|
|
150
151
|
}, [currentMetadataValues]);
|
|
151
152
|
const openFormHandler = (layoutMode) => { setIsOpenDcmtForm(true); setDcmtFormLayoutMode(layoutMode); };
|
|
152
|
-
const openSharedArchiveHandler = () => {
|
|
153
|
+
const openSharedArchiveHandler = async () => {
|
|
153
154
|
const dcmts = getSelectedDcmtsOrFocused(selectedItems, focusedItem);
|
|
154
155
|
if (dcmts.length === 0) {
|
|
155
|
-
ShowAlert({ message: "Nessun documento selezionato", mode: "warning", duration: 3000 });
|
|
156
|
+
ShowAlert({ message: "Nessun documento selezionato", mode: "warning", title: 'Archivio Condivisa', duration: 3000 });
|
|
156
157
|
return;
|
|
157
158
|
}
|
|
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
|
+
}
|
|
167
|
+
}
|
|
168
|
+
catch (error) {
|
|
169
|
+
ShowAlert({ message: 'Il Documenti ha solo i metadati', mode: "warning", title: 'Archivio Condivisa', duration: 5000 });
|
|
170
|
+
}
|
|
158
171
|
setIsOpenSharedArchive(true);
|
|
159
172
|
};
|
|
160
173
|
const openTaskFormHandler = (onTaskCreated) => {
|
|
@@ -608,7 +621,7 @@ const TMSearchResult = ({ context = SearchResultContext.METADATA_SEARCH, isVisib
|
|
|
608
621
|
await onRefreshSearchAsync?.();
|
|
609
622
|
} }), isOpenSharedArchive && _jsx(TMModal, { title: "Archiviazione condivisa", onClose: () => {
|
|
610
623
|
setIsOpenSharedArchive(false);
|
|
611
|
-
}, width: isMobile ? '90%' : '80%', height: isMobile ? '90%' : '80%', children: _jsx(TMArchive, { inputTID: focusedItem?.TID, inputMids: currentMetadataValues.filter(md => md.mid && md.mid > 100).map(md => ({ mid: md.mid, value: md.value ?? '' })), isSharedArchive: true, onSavedAsyncCallback: async (tid, did) => {
|
|
624
|
+
}, width: isMobile ? '90%' : '80%', height: isMobile ? '90%' : '80%', children: _jsx(TMArchive, { inputTID: focusedItem?.TID, inputMids: currentMetadataValues.filter(md => md.mid && md.mid > 100).map(md => ({ mid: md.mid, value: md.value ?? '' })), isSharedArchive: true, inputFile: sharedDcmtFile, onSavedAsyncCallback: async (tid, did) => {
|
|
612
625
|
setIsOpenSharedArchive(false);
|
|
613
626
|
await onRefreshSearchAsync?.();
|
|
614
627
|
} }) })] }));
|
|
@@ -4,7 +4,7 @@ import { TMDataGridContextMenuItem } from '../../base/TMDataGrid';
|
|
|
4
4
|
import { DcmtInfo, DcmtOperationTypes, DownloadModes, DownloadTypes, SearchResultContext } from '../../../ts';
|
|
5
5
|
export declare const getSelectedDcmtsOrFocused: (selectedItems: Array<any>, focusedItem: any, fileFormat?: FileFormats) => DcmtInfo[];
|
|
6
6
|
export declare const signatureInformationCallback: (isMobile: boolean, inputDcmts: DcmtInfo[] | undefined) => Promise<void>;
|
|
7
|
-
export declare const getCommandsMenuItems: (isMobile: boolean, dtd: DcmtTypeDescriptor | undefined, selectedItems: Array<any>, focusedItem: any, context: SearchResultContext, showFloatingBar: boolean, workingGroupContext: WorkingGroupDescriptor | undefined, showSearch: boolean, setShowFloatingBar: React.Dispatch<React.SetStateAction<boolean>>, openFormHandler: (layoutMode: LayoutModes) => void, openSharedArchiveHandler: () => void
|
|
7
|
+
export declare const getCommandsMenuItems: (isMobile: boolean, dtd: DcmtTypeDescriptor | undefined, selectedItems: Array<any>, focusedItem: any, context: SearchResultContext, showFloatingBar: boolean, workingGroupContext: WorkingGroupDescriptor | undefined, showSearch: boolean, setShowFloatingBar: React.Dispatch<React.SetStateAction<boolean>>, openFormHandler: (layoutMode: LayoutModes) => void, openSharedArchiveHandler: () => Promise<void>, downloadDcmtsAsync: (inputDcmts: DcmtInfo[] | undefined, downloadType: DownloadTypes, downloadMode: DownloadModes, onFileDownloaded?: (dcmtFile: File | undefined) => void, confirmAttachments?: (list: FileDescriptor[]) => Promise<string[] | undefined>) => Promise<void>, runOperationAsync: (inputDcmts: DcmtInfo[] | undefined, dcmtOperationType: DcmtOperationTypes, actionAfterOperationAsync?: () => Promise<void>) => Promise<void>, onRefreshSearchAsync: (() => Promise<void>) | undefined, onRefreshDataRowsAsync: (() => Promise<void>) | undefined, onRefreshAfterAddDcmtToFavs: (() => void) | undefined, confirmFormat: () => Promise<FileFormats>, confirmAttachments: (list: FileDescriptor[]) => Promise<string[] | undefined>, openTaskFormHandler: () => void, openDetailDcmtsFormHandler: (value: boolean) => void, openMasterDcmtsFormHandler: (value: boolean) => void, openBatchUpdateFormHandler: (value: boolean) => void, openExportForm: () => void, handleToggleSearch: () => void, handleSignApprove: () => void, openWGsCopyMoveForm?: ((mode: "copyToWgDraft" | "copyToWgArchivedDoc", dcmtTypeDescriptor: DcmtTypeDescriptor, documents: Array<DcmtInfo>) => void), openCommentFormCallback?: ((documents: Array<DcmtInfo>) => void), openEditPdf?: ((documents: Array<DcmtInfo>) => void), openAddDocumentForm?: () => void, passToArchiveCallback?: (outputMids: Array<{
|
|
8
8
|
mid: number;
|
|
9
9
|
value: string;
|
|
10
10
|
}>) => void, archiveMasterDocuments?: (tid: number | undefined) => Promise<void>, archiveDetailDocuments?: (tid: number | undefined) => Promise<void>, hasMasterRelation?: boolean, hasDetailRelation?: boolean, canArchiveMasterRelation?: boolean, canArchiveDetailRelation?: boolean, pairManyToManyDocuments?: (isPairing: boolean) => Promise<void>, hasManyToManyRelation?: boolean) => Array<TMDataGridContextMenuItem>;
|
|
@@ -406,13 +406,13 @@ export const getCommandsMenuItems = (isMobile, dtd, selectedItems, focusedItem,
|
|
|
406
406
|
text: "Archiviazione condivisa",
|
|
407
407
|
operationType: 'singleRow',
|
|
408
408
|
disabled: disabledForSingleRow(selectedItems, focusedItem),
|
|
409
|
-
onClick: () => { openSharedArchiveHandler(); }
|
|
409
|
+
onClick: async () => { await openSharedArchiveHandler(); }
|
|
410
410
|
},
|
|
411
411
|
{
|
|
412
412
|
icon: svgToString(_jsx(IconSharedDcmt, {})),
|
|
413
413
|
text: "Mostra documenti condivisi",
|
|
414
414
|
operationType: 'multiRow',
|
|
415
|
-
disabled:
|
|
415
|
+
disabled: disabledForMultiRow(selectedItems, focusedItem),
|
|
416
416
|
onClick: () => ShowAlert({ message: "TODO Mostra documenti condivisi", mode: 'info', title: `${"TODO"}`, duration: 3000 })
|
|
417
417
|
}
|
|
418
418
|
]
|
|
@@ -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}}
|
|
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}}
|
|
1281
|
+
return "Die Beschreibung ist zu lang: {{0}} Zeichen zu viel";
|
|
1282
1282
|
case CultureIDs.En_US:
|
|
1283
|
-
return "Description is too long: {{0}}
|
|
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}}
|
|
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}}
|
|
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}}
|
|
1289
|
+
return "A descrição é demasiado longa: {{0}} caracteres a mais";
|
|
1290
1290
|
default:
|
|
1291
|
-
return "La descrizione è troppo lunga: {{0}}
|
|
1291
|
+
return "La descrizione è troppo lunga: {{0}} caratteri in più";
|
|
1292
1292
|
}
|
|
1293
1293
|
}
|
|
1294
1294
|
static get DescriptionTooLongMessage() {
|
|
@@ -346,9 +346,11 @@ export const useRelatedDocuments = ({ selectedSearchResult, focusedItem, current
|
|
|
346
346
|
const searchEngine = SDK_Globals.tmSession?.NewSearchEngine();
|
|
347
347
|
if (!focusedItem?.TID || !focusedItem?.DID) {
|
|
348
348
|
ShowAlert({
|
|
349
|
-
message:
|
|
349
|
+
message: isPairing
|
|
350
|
+
? "Nessun documento selezionato per l'abbinamento molti a molti."
|
|
351
|
+
: "Nessun documento selezionato per il disabbinamento molti a molti.",
|
|
350
352
|
mode: 'warning',
|
|
351
|
-
title: '
|
|
353
|
+
title: isPairing ? 'Abbina documenti molti a molti' : 'Disabbina documenti molti a molti',
|
|
352
354
|
duration: 5000
|
|
353
355
|
});
|
|
354
356
|
return;
|
|
@@ -363,9 +365,11 @@ export const useRelatedDocuments = ({ selectedSearchResult, focusedItem, current
|
|
|
363
365
|
}
|
|
364
366
|
if (!qd) {
|
|
365
367
|
ShowAlert({
|
|
366
|
-
message:
|
|
368
|
+
message: isPairing
|
|
369
|
+
? "Nessuna query di recupero associata alla relazione di abbinamento molti a molti."
|
|
370
|
+
: "Nessuna query di recupero associata alla relazione di disabbinamento molti a molti.",
|
|
367
371
|
mode: 'warning',
|
|
368
|
-
title: '
|
|
372
|
+
title: isPairing ? 'Abbina documenti molti a molti' : 'Disabbina documenti molti a molti',
|
|
369
373
|
duration: 5000
|
|
370
374
|
});
|
|
371
375
|
return;
|
|
@@ -470,7 +474,7 @@ export const useRelatedDocuments = ({ selectedSearchResult, focusedItem, current
|
|
|
470
474
|
ShowAlert({
|
|
471
475
|
message: "Nessun documento abbinato trovato.",
|
|
472
476
|
mode: 'warning',
|
|
473
|
-
title: '
|
|
477
|
+
title: 'Disabbina documenti molti a molti',
|
|
474
478
|
duration: 5000
|
|
475
479
|
});
|
|
476
480
|
return;
|
|
@@ -494,7 +498,7 @@ export const useRelatedDocuments = ({ selectedSearchResult, focusedItem, current
|
|
|
494
498
|
ShowAlert({
|
|
495
499
|
message: "Nessun documento trovato.",
|
|
496
500
|
mode: 'warning',
|
|
497
|
-
title: '
|
|
501
|
+
title: 'Abbina documenti molti a molti',
|
|
498
502
|
duration: 5000
|
|
499
503
|
});
|
|
500
504
|
openPairSearchModal(relation, targetTID, qd);
|
|
@@ -519,7 +523,7 @@ export const useRelatedDocuments = ({ selectedSearchResult, focusedItem, current
|
|
|
519
523
|
ShowAlert({
|
|
520
524
|
message: "Nessun documento da abbinare. Tutti i documenti risultanti sono già abbinati.",
|
|
521
525
|
mode: 'warning',
|
|
522
|
-
title: '
|
|
526
|
+
title: 'Abbina documenti molti a molti',
|
|
523
527
|
duration: 5000
|
|
524
528
|
});
|
|
525
529
|
openPairSearchModal(relation, targetTID, qd);
|
|
@@ -537,9 +541,11 @@ export const useRelatedDocuments = ({ selectedSearchResult, focusedItem, current
|
|
|
537
541
|
return;
|
|
538
542
|
if (!relations.some(r => r.relationType === RelationTypes.ManyToMany)) {
|
|
539
543
|
ShowAlert({
|
|
540
|
-
message:
|
|
544
|
+
message: isPairing
|
|
545
|
+
? "Nessuna relazione di abbinamento molti a molti definita nel sistema."
|
|
546
|
+
: "Nessuna relazione di disabbinamento molti a molti definita nel sistema.",
|
|
541
547
|
mode: 'warning',
|
|
542
|
-
title: '
|
|
548
|
+
title: isPairing ? 'Abbina documenti molti a molti' : 'Disabbina documenti molti a molti',
|
|
543
549
|
duration: 5000
|
|
544
550
|
});
|
|
545
551
|
return;
|
|
@@ -547,9 +553,11 @@ export const useRelatedDocuments = ({ selectedSearchResult, focusedItem, current
|
|
|
547
553
|
const manyToManyRels = relations.filter(r => r.relationType === RelationTypes.ManyToMany);
|
|
548
554
|
if (!manyToManyRels.some(r => r.masterTID === selectedSearchResult?.fromTID || r.detailTID === selectedSearchResult?.fromTID)) {
|
|
549
555
|
ShowAlert({
|
|
550
|
-
message:
|
|
556
|
+
message: isPairing
|
|
557
|
+
? "Nessuna relazione di abbinamento molti a molti definita per il tipo di documento selezionato."
|
|
558
|
+
: "Nessuna relazione di disabbinamento molti a molti definita per il tipo di documento selezionato.",
|
|
551
559
|
mode: 'warning',
|
|
552
|
-
title: '
|
|
560
|
+
title: isPairing ? 'Abbina documenti molti a molti' : 'Disabbina documenti molti a molti',
|
|
553
561
|
duration: 5000
|
|
554
562
|
});
|
|
555
563
|
return;
|