@topconsultnpm/sdkui-react 6.19.0-dev1.40 → 6.19.0-dev1.42

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.
@@ -11,6 +11,8 @@ export const sanitizeAndFormatComment = (raw = "") => {
11
11
  if (!raw)
12
12
  return "";
13
13
  let cleanComment = raw
14
+ // Simplify dx-mention markup - replace with just @username
15
+ .replace(/<span class="dx-mention"[^>]*>\uFEFF?<span[^>]*><span>@<\/span>([^<]+)<\/span>\uFEFF?<\/span>/gi, '@$1')
14
16
  // Replace </p> with '' only if followed by <ol> or <ul>
15
17
  .replace(/<\/p>(?=\s*<(ol|ul)>)/gi, '')
16
18
  // Replace all other </p> with '\r\n'
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
- import React, { useEffect, useState } from "react";
2
+ import React, { useCallback, useEffect, useMemo, useState } from "react";
3
3
  import styled from "styled-components";
4
4
  import { AccessLevels, DcmtTypeListCacheService, LayoutItemTypes, LayoutModes, MetadataDataDomains, MetadataDataTypes, SDK_Globals, SystemMIDsAsNumber, SystemTIDs, TemplateTIDs, WorkItemMetadataNames } from '@topconsultnpm/sdk-ts';
5
5
  import { IconUndo, IconPencil, IconFunction, IconMenuVertical, IconDataList, SDKUI_Localizator, IconNull, stringIsNullOrEmpty, deepCompare, SDKUI_Globals, IconDcmtTypeSys } from "../../helper";
@@ -33,7 +33,7 @@ const TMMetadataValues = ({ showCheckBoxes = ShowCheckBoxesMode.Never, checkPerm
33
33
  const [selectedItem, setSelectedItem] = useState(undefined);
34
34
  const [prevMetadataValues, setPrevMetadataValues] = useState([]);
35
35
  const [inputMidsApplied, setInputMidsApplied] = useState(false);
36
- const onChangeHandler = (newValue, mid) => {
36
+ const onChangeHandler = useCallback((newValue, mid) => {
37
37
  let newValues = structuredClone(metadataValues);
38
38
  const item = newValues.find(value => value.mid === mid);
39
39
  if (item) {
@@ -51,25 +51,25 @@ const TMMetadataValues = ({ showCheckBoxes = ShowCheckBoxesMode.Never, checkPerm
51
51
  }
52
52
  }
53
53
  onValueChanged?.(newValues);
54
- };
55
- const editorValidationHandler = (mid) => {
54
+ }, [metadataValues, showCheckBoxes, dynDataListsToBeRefreshed, onValueChanged]);
55
+ const editorValidationHandler = useCallback((mid) => {
56
56
  const md = metadataValues?.find(m => m.mid === mid);
57
57
  const validationItem = validationItems.find(vil => vil.PropertyName === md?.md?.nameLoc);
58
58
  return validationItem ? [validationItem] : [];
59
- };
60
- const isEditable = (mid) => {
59
+ }, [metadataValues, validationItems]);
60
+ const isEditable = useCallback((mid) => {
61
61
  let md = currentDTD?.metadata?.find(o => o.id == mid);
62
62
  if (!md)
63
63
  return false;
64
64
  let isList = md.dataDomain == MetadataDataDomains.DataList || md.dataDomain == MetadataDataDomains.DynamicDataList || md.dataDomain == MetadataDataDomains.UserID;
65
65
  return isList && isEditableList(mid);
66
- };
67
- const handleMetadataValueSelection = (item) => {
66
+ }, [currentDTD, isEditableList]);
67
+ const handleMetadataValueSelection = useCallback((item) => {
68
68
  if (selectedItem?.mid !== item.mid) {
69
69
  setSelectedItem(item);
70
70
  onFocusedItemChanged?.(item);
71
71
  }
72
- };
72
+ }, [selectedItem, onFocusedItemChanged]);
73
73
  useEffect(() => {
74
74
  if (!TID) {
75
75
  setCurrentDTD(undefined);
@@ -184,7 +184,7 @@ const TMMetadataValues = ({ showCheckBoxes = ShowCheckBoxesMode.Never, checkPerm
184
184
  }
185
185
  return toBeRefreshed;
186
186
  };
187
- const getAdvancedMenuItems = (mvd) => {
187
+ const getAdvancedMenuItems = useCallback((mvd) => {
188
188
  let md = mvd.md;
189
189
  if (!md)
190
190
  return [];
@@ -241,9 +241,9 @@ const TMMetadataValues = ({ showCheckBoxes = ShowCheckBoxesMode.Never, checkPerm
241
241
  ...customMenuItems
242
242
  ];
243
243
  return menu;
244
- };
244
+ }, [checkPerms, isExpertMode, customMenuItems, metadataValues, onAdvancedMenuClick, onValueChanged]);
245
245
  // Helper function to render a single metadata item
246
- const renderMetadataItem = (item, isReadOnlyOverride = false) => (_jsxs(StyledRow, { style: { marginTop: item.md?.dataType === MetadataDataTypes.DateTime ? '6px' : '0', gap: '8px' }, onClick: () => { handleMetadataValueSelection(item); }, onFocus: () => { handleMetadataValueSelection(item); }, children: [showCheckBoxes !== ShowCheckBoxesMode.Never &&
246
+ const renderMetadataItem = useCallback((item, isReadOnlyOverride = false) => (_jsxs(StyledRow, { style: { marginTop: item.md?.dataType === MetadataDataTypes.DateTime ? '6px' : '0', gap: '8px' }, onClick: () => { handleMetadataValueSelection(item); }, onFocus: () => { handleMetadataValueSelection(item); }, children: [showCheckBoxes !== ShowCheckBoxesMode.Never &&
247
247
  _jsx(TMCheckBox, { elementStyle: { marginTop: item.md?.dataType === MetadataDataTypes.DateTime ? '14px' : '20px' }, value: item.isSelected, disabled: showCheckBoxes === ShowCheckBoxesMode.AlwaysReadOnly, onValueChanged: (newValue) => {
248
248
  let newValues = structuredClone(metadataValues);
249
249
  const mvd = newValues.find(value => value.mid === item.mid);
@@ -296,8 +296,8 @@ const TMMetadataValues = ({ showCheckBoxes = ShowCheckBoxesMode.Never, checkPerm
296
296
  mvd.isSelected = !stringIsNullOrEmpty(mvd.value);
297
297
  }
298
298
  onValueChanged?.(newValues);
299
- } }) }), !isReadOnly && _jsx("div", { style: { marginTop: item.md?.dataType === MetadataDataTypes.DateTime ? '12px' : '18px' }, onClick: () => { handleMetadataValueSelection(item); }, children: _jsx(TMDropDownMenu, { backgroundColor: 'white', color: TMColors.button_icon, borderRadius: '3px', content: _jsx(TMButton, { btnStyle: 'icon', icon: _jsx(IconMenuVertical, {}), showTooltip: false }), disabled: item.isLexProt === 1, items: getAdvancedMenuItems(item) }) })] }, item.mid));
300
- const layoutWorkItem = () => {
299
+ } }) }), !isReadOnly && _jsx("div", { style: { marginTop: item.md?.dataType === MetadataDataTypes.DateTime ? '12px' : '18px' }, onClick: () => { handleMetadataValueSelection(item); }, children: _jsx(TMDropDownMenu, { backgroundColor: 'white', color: TMColors.button_icon, borderRadius: '3px', content: _jsx(TMButton, { btnStyle: 'icon', icon: _jsx(IconMenuVertical, {}), showTooltip: false }), disabled: item.isLexProt === 1, items: getAdvancedMenuItems(item) }) })] }, item.mid)), [TID, showCheckBoxes, showNullValueCheckBoxes, isReadOnly, layoutMode, selectedMID, isOpenDistinctValues, openChooserBySingleClick, dynDataListsToBeRefreshed, metadataValues, metadataValuesOrig, validationItems, onValueChanged, handleMetadataValueSelection, getAdvancedMenuItems, onChangeHandler, editorValidationHandler, isEditable]);
300
+ const layoutWorkItem = useMemo(() => {
301
301
  const workItemData = [];
302
302
  const technicalWorkItemData = [];
303
303
  const documentData = [];
@@ -328,8 +328,8 @@ const TMMetadataValues = ({ showCheckBoxes = ShowCheckBoxesMode.Never, checkPerm
328
328
  }
329
329
  });
330
330
  return (_jsxs("div", { style: { width: '100%' }, children: [documentData.length > 0 && _jsx(TMAccordion, { title: SDKUI_Localizator.DocumentData, children: documentData.map(item => renderMetadataItem(item)) }), workItemData.length > 0 && _jsx(TMAccordion, { title: SDKUI_Localizator.WorkItemData, children: workItemData.map(item => renderMetadataItem(item, true)) }), technicalWorkItemData.length > 0 && _jsx(TMAccordion, { title: SDKUI_Localizator.WorkItemTechnicalData, defaultCollapsed: true, children: technicalWorkItemData.map(item => renderMetadataItem(item, true)) })] }));
331
- };
332
- const layoutDraft = () => {
331
+ }, [metadataValues, showCheckBoxes, showNullValueCheckBoxes, isReadOnly, dynDataListsToBeRefreshed, validationItems, selectedMID, isOpenDistinctValues, openChooserBySingleClick, metadataValuesOrig]);
332
+ const layoutDraft = useMemo(() => {
333
333
  // Definiamo l'ordine desiderato per gli elementi
334
334
  const desiredDraftOrder = [
335
335
  DraftsMIDs.Name,
@@ -385,8 +385,8 @@ const TMMetadataValues = ({ showCheckBoxes = ShowCheckBoxesMode.Never, checkPerm
385
385
  }
386
386
  });
387
387
  return (_jsxs("div", { style: { width: '100%' }, children: [draftData.length > 0 && _jsx(TMAccordion, { title: SDKUI_Localizator.Draft, children: draftData.map(item => renderMetadataItem(item, isReadOnly)) }), checkOutData.length > 0 && _jsx(TMAccordion, { title: `${SDKUI_Localizator.CheckIn}/${SDKUI_Localizator.CheckOut}`, children: checkOutData.map(item => renderMetadataItem(item, true)) })] }));
388
- };
389
- const layoutDsAttachs = () => {
388
+ }, [metadataValues, showCheckBoxes, showNullValueCheckBoxes, isReadOnly, dynDataListsToBeRefreshed, validationItems, selectedMID, isOpenDistinctValues, openChooserBySingleClick, metadataValuesOrig]);
389
+ const layoutDsAttachs = useMemo(() => {
390
390
  const dsAttachsData = [];
391
391
  metadataValues.forEach(item => {
392
392
  switch (item.md?.id) {
@@ -400,8 +400,8 @@ const TMMetadataValues = ({ showCheckBoxes = ShowCheckBoxesMode.Never, checkPerm
400
400
  }
401
401
  });
402
402
  return (_jsx("div", { style: { width: '100%' }, children: dsAttachsData.length > 0 && _jsx(TMAccordion, { title: SDKUI_Localizator.Attachment, children: dsAttachsData.map(item => renderMetadataItem(item, isReadOnly)) }) }));
403
- };
404
- const layoutCustom = () => {
403
+ }, [metadataValues, showCheckBoxes, showNullValueCheckBoxes, isReadOnly, dynDataListsToBeRefreshed, validationItems, selectedMID, isOpenDistinctValues, openChooserBySingleClick, metadataValuesOrig]);
404
+ const layoutCustom = useMemo(() => {
405
405
  if (!layout || !layout.items || layout.items.length === 0) {
406
406
  return metadataValues.map((item) => renderMetadataItem(item));
407
407
  }
@@ -413,15 +413,20 @@ const TMMetadataValues = ({ showCheckBoxes = ShowCheckBoxesMode.Never, checkPerm
413
413
  }
414
414
  });
415
415
  // Find root items (items without parent or parent === 0)
416
- const rootItems = layout.items.filter(item => !item.parentID || item.parentID === 0);
416
+ const rootItems = layout.items.filter(item => item.type === LayoutItemTypes.LayoutRoot);
417
417
  // Recursive function to get children of an item
418
418
  const getChildren = (parentID) => {
419
419
  return layout.items?.filter(item => item.parentID === parentID) || [];
420
420
  };
421
421
  // Recursive function to render layout items with depth tracking for indentation
422
422
  const renderLayoutItem = (layoutItem, depth = 0) => {
423
+ // Check if this is a LayoutRoot - just render its children
424
+ if (layoutItem.type === LayoutItemTypes.LayoutRoot) {
425
+ const children = getChildren(layoutItem.layoutItemID ?? 0);
426
+ return (_jsx(React.Fragment, { children: children.map(child => renderLayoutItem(child, depth)) }, `root-${layoutItem.layoutItemID}`));
427
+ }
423
428
  // Check if this is a LayoutGroup
424
- if (layoutItem.type === LayoutItemTypes.LayoutGroup && layoutItem.lgd) {
429
+ else if (layoutItem.type === LayoutItemTypes.LayoutGroup && layoutItem.lgd) {
425
430
  const children = getChildren(layoutItem.layoutItemID ?? 0);
426
431
  const groupDescriptor = layoutItem.lgd;
427
432
  const groupTitle = groupDescriptor.caption || `Group ${layoutItem.layoutItemID}`;
@@ -440,8 +445,9 @@ const TMMetadataValues = ({ showCheckBoxes = ShowCheckBoxesMode.Never, checkPerm
440
445
  const metadataItem = metadataValues.find(m => m.mid === mid);
441
446
  if (!metadataItem)
442
447
  return null;
443
- // No indentation for control items - they maintain their original styling
444
- return (_jsx(React.Fragment, { children: renderMetadataItem(metadataItem) }, `control-${layoutItem.layoutItemID}`));
448
+ // Indent control items based on depth so they align under groups
449
+ const controlIndentPx = depth > 0 ? depth * 10 : 15;
450
+ return (_jsx("div", { style: { paddingLeft: `${controlIndentPx}px` }, children: renderMetadataItem(metadataItem) }, `control-${layoutItem.layoutItemID}`));
445
451
  }
446
452
  // Check if this is a SeparatorItem (horizontal line)
447
453
  else if (layoutItem.type === LayoutItemTypes.SeparatorItem) {
@@ -450,31 +456,35 @@ const TMMetadataValues = ({ showCheckBoxes = ShowCheckBoxesMode.Never, checkPerm
450
456
  return null;
451
457
  };
452
458
  return (_jsx("div", { style: { width: '100%' }, children: rootItems.map(item => renderLayoutItem(item, 0)) }));
453
- };
454
- const renderForm = () => {
459
+ }, [layout, metadataValues, showCheckBoxes, showNullValueCheckBoxes, isReadOnly, dynDataListsToBeRefreshed, validationItems, selectedMID, isOpenDistinctValues, openChooserBySingleClick, metadataValuesOrig]);
460
+ const renderForm = useMemo(() => {
461
+ // Se currentDTD non è ancora stato caricato, non renderizzare nulla
462
+ if (!currentDTD) {
463
+ return null;
464
+ }
455
465
  // Se tutti i metadata sono di sistema, renderizziamo tutti in sola lettura senza layout
456
466
  const allSystem = metadataValues.length > 0 && metadataValues.every(item => item.md?.isSystem === 1);
457
467
  if (allSystem) {
458
468
  return metadataValues.map((item) => renderMetadataItem(item, true));
459
469
  }
460
470
  if (currentDTD?.templateTID === TemplateTIDs.WF_WIApprView && !isReadOnly) {
461
- return layoutWorkItem();
471
+ return layoutWorkItem;
462
472
  }
463
473
  switch (currentDTD?.id) {
464
- case SystemTIDs.Drafts: return layoutDraft();
474
+ case SystemTIDs.Drafts: return layoutDraft;
465
475
  // case SystemTIDs.Chronology: break;
466
- case SystemTIDs.DSAttachs: return layoutDsAttachs();
476
+ case SystemTIDs.DSAttachs: return layoutDsAttachs;
467
477
  default:
468
478
  // Se è presente un layout personalizzato, usalo, altrimenti usa il rendering standard
469
479
  if (layout && layout.items && layout.items.length > 0) {
470
- return layoutCustom();
480
+ return layoutCustom;
471
481
  }
472
482
  return metadataValues.map((item) => renderMetadataItem(item));
473
483
  }
474
- };
484
+ }, [currentDTD, metadataValues, layout, isReadOnly, showCheckBoxes, showNullValueCheckBoxes, dynDataListsToBeRefreshed, validationItems, selectedMID, isOpenDistinctValues, openChooserBySingleClick, metadataValuesOrig]);
475
485
  return (_jsx(StyledMetadataValuesContainer, { children: !TID ?
476
486
  _jsx(TMNothingToShow, { text: `${SDKUI_Localizator.NoDcmtSelected}.`, secondText: `${SDKUI_Localizator.MetadataSystem} - ${SDKUI_Localizator.NotAvailable}`, icon: _jsx(IconDcmtTypeSys, { fontSize: 96 }) }) :
477
- _jsx(_Fragment, { children: renderForm() }) }));
487
+ _jsx(_Fragment, { children: renderForm }) }));
478
488
  };
479
489
  export default TMMetadataValues;
480
490
  //#region Styled Components
@@ -113,7 +113,7 @@ const TMBlogCommentForm = (props) => {
113
113
  const blogPost = new BlogPost();
114
114
  // Retrieve the comment from formData, or use an empty string if undefined
115
115
  const comment = formData?.comment ?? "";
116
- // Clean the comment by removing <p> tags and replacing </p> with line breaks
116
+ // Clean the comment using the sanitizeAndFormatComment function
117
117
  const cleanComment = sanitizeAndFormatComment(comment);
118
118
  // Assign the cleaned comment as the description for the blog post
119
119
  blogPost.description = cleanComment ?? "";
@@ -8,7 +8,7 @@ import { DownloadTypes, FormModes } from '../../../ts';
8
8
  import { DeviceType, useDeviceType } from '../../base/TMDeviceProvider';
9
9
  import { useDcmtOperations } from '../../../hooks/useDcmtOperations';
10
10
  import { getWorkItemSetIDAsync, handleArchiveVisibility, searchResultToMetadataValues } from '../../../helper/queryHelper';
11
- import { genUniqueId, IconShow, SDKUI_Localizator, updateMruTids, IconBoard, IconDcmtTypeSys, IconDetailDcmts, svgToString, IconDownload, calcIsModified, IconMenuVertical, Globalization, getListMaxItems, getSystemMetadata, IconBoxArchiveIn, IconClear, IconUndo, SDKUI_Globals, IconPreview, isTaskMoreInfo, IconWorkflow, IconSearch, deepCompare } from '../../../helper';
11
+ import { genUniqueId, IconShow, SDKUI_Localizator, updateMruTids, IconBoard, IconDcmtTypeSys, IconDetailDcmts, svgToString, IconDownload, calcIsModified, IconMenuVertical, Globalization, getListMaxItems, getSystemMetadata, IconBoxArchiveIn, IconClear, IconUndo, SDKUI_Globals, IconPreview, isTaskMoreInfo, IconWorkflow, IconSearch, deepCompare, IconCheck } from '../../../helper';
12
12
  import { hasDetailRelations, hasMasterRelations, isXMLFileExt } from '../../../helper/dcmtsHelper';
13
13
  import { Gutters, TMColors } from '../../../utils/theme';
14
14
  import { StyledFormButtonsContainer, StyledLoadingContainer, StyledModalContainer, StyledSpinner, StyledToolbarCardContainer } from '../../base/Styled';
@@ -59,6 +59,7 @@ const TMDcmtForm = ({ showHeader = true, onSaveRecents, layoutMode = LayoutModes
59
59
  const [showReAssignPopup, setShowReAssignPopup] = useState(false);
60
60
  const [showMoreInfoPopup, setShowMoreInfoPopup] = useState(false);
61
61
  const [layout, setLayout] = useState();
62
+ const [customButtonsLayout, setCustomButtonsLayout] = useState();
62
63
  const appliedInputMidsRef = useRef(null);
63
64
  // Refs per evitare stale closure nei callback
64
65
  // I useCallback catturano i valori delle dipendenze al momento della creazione.
@@ -153,10 +154,26 @@ const TMDcmtForm = ({ showHeader = true, onSaveRecents, layoutMode = LayoutModes
153
154
  return;
154
155
  if (!DID && layoutMode === LayoutModes.Update)
155
156
  return;
156
- let getMetadataResult;
157
- if (layoutMode === LayoutModes.Update) {
158
- getMetadataResult = await SDK_Globals.tmSession?.NewSearchEngine().GetMetadataAsync(TID, DID, true);
157
+ // Esegui chiamate in parallelo per ottimizzare le performance
158
+ const parallelCalls = [
159
+ // 1. GetMetadataAsync - solo se layoutMode === Update
160
+ layoutMode === LayoutModes.Update
161
+ ? SDK_Globals.tmSession?.NewSearchEngine().GetMetadataAsync(TID, DID, true) ?? Promise.resolve(undefined)
162
+ : Promise.resolve(undefined),
163
+ // 2. Layout per il layoutMode corrente
164
+ LayoutCacheService.GetAsync(TID, layoutMode),
165
+ // 3. CustomButtonsLayout - solo se layoutMode === Update
166
+ layoutMode === LayoutModes.Update
167
+ ? LayoutCacheService.GetAsync(TID, LayoutModes.None)
168
+ : Promise.resolve(undefined)
169
+ ];
170
+ const [getMetadataResult, resLayout, customButtonsLayoutResult] = await Promise.all(parallelCalls);
171
+ // Imposta il layout e customButtonsLayout immediatamente
172
+ setLayout(resLayout);
173
+ if (layoutMode === LayoutModes.Update && customButtonsLayoutResult) {
174
+ setCustomButtonsLayout(customButtonsLayoutResult);
159
175
  }
176
+ // Carica DTD e metadata
160
177
  let dtd = await DcmtTypeListCacheService.GetWithNotGrantedAsync(TID, DID, getMetadataResult);
161
178
  setFromDTD(dtd);
162
179
  if (layoutMode === LayoutModes.Update || (layoutMode === LayoutModes.Ark && DID)) {
@@ -169,8 +186,6 @@ const TMDcmtForm = ({ showHeader = true, onSaveRecents, layoutMode = LayoutModes
169
186
  setFormData(structuredClone(metadataList));
170
187
  formDataOrigRef.current = structuredClone(metadataList);
171
188
  }
172
- let resLayout = await LayoutCacheService.GetAsync(TID, layoutMode);
173
- setLayout(resLayout);
174
189
  (layoutMode === LayoutModes.Ark && !inputFile) && handleReset();
175
190
  }
176
191
  catch (e) {
@@ -420,14 +435,36 @@ const TMDcmtForm = ({ showHeader = true, onSaveRecents, layoutMode = LayoutModes
420
435
  const isApprView = useMemo(() => fromDTD?.templateTID === TemplateTIDs.WF_WIApprView, [fromDTD?.templateTID]);
421
436
  const workitemSetID = useMemo(() => workItems.find(o => o.did === Number(DID))?.setID || formData.find(o => o.md?.name === WorkItemMetadataNames.WI_SetID)?.value, [workItems, DID, formData]);
422
437
  const approvalVID = useMemo(() => workItems.length > 0 ? Number(workItems[0].tid) : -1, [workItems]);
423
- const commandsMenuItems = useMemo(() => [
424
- { icon: svgToString(_jsx(IconDownload, {})), operationType: 'singleRow', disabled: fromDTD?.perm?.canRetrieveFile !== AccessLevels.Yes, text: "Download file", onClick: async () => await downloadDcmtsAsync(getDcmts(), DownloadTypes.Dcmt, "download") },
425
- { icon: svgToString(_jsx(IconDownload, {})), operationType: 'singleRow', disabled: !isXMLFileExt(currentDcmt?.fileExt), text: "Download allegati XML", onClick: async () => await downloadDcmtsAsync(getDcmts(), DownloadTypes.Attachment, "download", undefined, openConfirmAttachmentsDialog) },
426
- ...(allowRelations && currentTIDHasMasterRelations ? [{ icon: svgToString(_jsx(IconDetailDcmts, { transform: 'scale(-1, 1)' })), operationType: 'singleRow', disabled: isMasterDisabled, text: SDKUI_Localizator.DcmtsMaster, onClick: () => { if (!isMasterDisabled)
427
- setIsOpenMaster(!isOpenMaster); } }] : []),
428
- ...(allowRelations && currentTIDHasDetailRelations ? [{ icon: svgToString(_jsx(IconDetailDcmts, {})), operationType: 'singleRow', disabled: isDetailsDisabled, text: SDKUI_Localizator.DcmtsDetail, onClick: () => { if (!isDetailsDisabled)
429
- setIsOpenDetails(!isOpenDetails); } }] : []),
430
- ], [fromDTD?.perm?.canRetrieveFile, currentDcmt?.fileExt, allowRelations, currentTIDHasMasterRelations, isMasterDisabled, currentTIDHasDetailRelations, isDetailsDisabled, getDcmts, downloadDcmtsAsync, openConfirmAttachmentsDialog]);
438
+ const commandsMenuItems = useMemo(() => {
439
+ const items = [
440
+ { icon: svgToString(_jsx(IconDownload, {})), operationType: 'singleRow', disabled: fromDTD?.perm?.canRetrieveFile !== AccessLevels.Yes, text: "Download file", onClick: async () => await downloadDcmtsAsync(getDcmts(), DownloadTypes.Dcmt, "download") },
441
+ { icon: svgToString(_jsx(IconDownload, {})), operationType: 'singleRow', disabled: !isXMLFileExt(currentDcmt?.fileExt), text: "Download allegati XML", onClick: async () => await downloadDcmtsAsync(getDcmts(), DownloadTypes.Attachment, "download", undefined, openConfirmAttachmentsDialog) },
442
+ ...(allowRelations && currentTIDHasMasterRelations ? [{ icon: svgToString(_jsx(IconDetailDcmts, { transform: 'scale(-1, 1)' })), operationType: 'singleRow', disabled: isMasterDisabled, text: SDKUI_Localizator.DcmtsMaster, onClick: () => { if (!isMasterDisabled)
443
+ setIsOpenMaster(!isOpenMaster); } }] : []),
444
+ ...(allowRelations && currentTIDHasDetailRelations ? [{ icon: svgToString(_jsx(IconDetailDcmts, {})), operationType: 'singleRow', disabled: isDetailsDisabled, text: SDKUI_Localizator.DcmtsDetail, onClick: () => { if (!isDetailsDisabled)
445
+ setIsOpenDetails(!isOpenDetails); } }] : []),
446
+ ];
447
+ // Aggiungi submenu "Bottoni personalizzati" se esistono customButtons
448
+ if (customButtonsLayout?.customButtons && Array.isArray(customButtonsLayout.customButtons) && customButtonsLayout.customButtons.length > 0) {
449
+ const customButtonsItems = customButtonsLayout.customButtons.map((customButton) => ({
450
+ text: customButton.title || 'Bottone personalizzato',
451
+ onClick: () => {
452
+ // Per ora, visualizziamo le proprietà del bottone in console e alert
453
+ console.log('Custom Button Properties:', customButton);
454
+ TMMessageBoxManager.show({
455
+ message: `Custom Button:\n${JSON.stringify(customButton, null, 2)}`,
456
+ buttons: [ButtonNames.OK],
457
+ });
458
+ }
459
+ }));
460
+ items.push({
461
+ icon: svgToString(_jsx(IconCheck, {})),
462
+ text: 'Bottoni personalizzati',
463
+ items: customButtonsItems
464
+ });
465
+ }
466
+ return items;
467
+ }, [fromDTD?.perm?.canRetrieveFile, currentDcmt?.fileExt, allowRelations, currentTIDHasMasterRelations, isMasterDisabled, currentTIDHasDetailRelations, isDetailsDisabled, customButtonsLayout, getDcmts, downloadDcmtsAsync, openConfirmAttachmentsDialog]);
431
468
  const isModified = useMemo(() => calcIsModified(formData, formDataOrig), [formData, formDataOrig]);
432
469
  const formToolbar = useMemo(() => _jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: '10px' }, children: [allowNavigation && canPrev != undefined && _jsx("p", { style: { textAlign: 'center', padding: '1px 4px', display: 'flex' }, children: `${itemIndex}/${count}` }), allowNavigation && canPrev != undefined && _jsx(TMSaveFormButtonPrevious, { btnStyle: 'icon', iconColor: 'white', isModified: isModified, formMode: formMode, canPrev: canPrev, onPrev: onPrev }), allowNavigation && canNext != undefined && _jsx(TMSaveFormButtonNext, { btnStyle: 'icon', iconColor: 'white', isModified: isModified, formMode: formMode, canNext: canNext, onNext: onNext }), layoutMode === LayoutModes.Update && _jsx(IconMenuVertical, { id: `commands-detail-${id}`, color: 'white', cursor: 'pointer' }), layoutMode === LayoutModes.Update && _jsx(ContextMenu, { showEvent: 'click', dataSource: commandsMenuItems, target: `#commands-detail-${id}` }), layoutMode === LayoutModes.Ark &&
433
470
  _jsx(TMTooltip, { content: SDKUI_Localizator.PassToSearch, position: 'bottom', children: _jsx(IconSearch, { style: { cursor: 'pointer' }, onClick: handlePassToSearch }) })] }), [allowNavigation, canPrev, canNext, itemIndex, count, isModified, formMode, onPrev, onNext, layoutMode, id, commandsMenuItems, handlePassToSearch]);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@topconsultnpm/sdkui-react",
3
- "version": "6.19.0-dev1.40",
3
+ "version": "6.19.0-dev1.42",
4
4
  "description": "",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\" && exit 1",
@@ -39,7 +39,7 @@
39
39
  "lib"
40
40
  ],
41
41
  "dependencies": {
42
- "@topconsultnpm/sdk-ts": "6.19.0-dev1.8",
42
+ "@topconsultnpm/sdk-ts": "6.19.0-dev1.9",
43
43
  "buffer": "^6.0.3",
44
44
  "devextreme": "25.1.4",
45
45
  "devextreme-react": "25.1.4",