@topconsultnpm/sdkui-react 6.20.0-test1 → 6.21.0-dev1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. package/lib/components/NewComponents/ContextMenu/styles.d.ts +3 -1
  2. package/lib/components/NewComponents/ContextMenu/styles.js +7 -5
  3. package/lib/components/NewComponents/FloatingMenuBar/TMFloatingMenuBar.js +7 -1
  4. package/lib/components/base/Styled.d.ts +4 -1
  5. package/lib/components/base/Styled.js +11 -3
  6. package/lib/components/base/TMPanel.js +6 -4
  7. package/lib/components/base/TMPopUp.js +4 -0
  8. package/lib/components/base/TMTreeView.d.ts +3 -1
  9. package/lib/components/base/TMTreeView.js +68 -21
  10. package/lib/components/base/TMWaitPanel.js +6 -5
  11. package/lib/components/choosers/TMDataListItemChooser.js +1 -1
  12. package/lib/components/choosers/TMDataListItemEditor.d.ts +11 -0
  13. package/lib/components/choosers/TMDataListItemEditor.js +130 -0
  14. package/lib/components/choosers/TMDataListItemFields.d.ts +11 -0
  15. package/lib/components/choosers/TMDataListItemFields.js +61 -0
  16. package/lib/components/choosers/TMDataListItemPicker.d.ts +2 -0
  17. package/lib/components/choosers/TMDataListItemPicker.js +182 -18
  18. package/lib/components/choosers/TMDynDataListItemChooser.js +11 -6
  19. package/lib/components/choosers/TMImageIDChooser.d.ts +16 -0
  20. package/lib/components/choosers/TMImageIDChooser.js +53 -0
  21. package/lib/components/choosers/TMMetadataChooser.js +1 -1
  22. package/lib/components/choosers/TMUserChooser.js +1 -1
  23. package/lib/components/editors/TMDateBox.js +1 -1
  24. package/lib/components/editors/TMHtmlEditor.js +1 -1
  25. package/lib/components/editors/TMLocalizedTextBox.d.ts +1 -0
  26. package/lib/components/editors/TMLocalizedTextBox.js +3 -3
  27. package/lib/components/editors/TMMetadataValues.js +203 -41
  28. package/lib/components/editors/TMTextArea.d.ts +1 -0
  29. package/lib/components/editors/TMTextArea.js +6 -6
  30. package/lib/components/editors/TMTextBox.js +9 -10
  31. package/lib/components/features/archive/TMArchive.d.ts +3 -1
  32. package/lib/components/features/archive/TMArchive.js +31 -44
  33. package/lib/components/features/blog/TMBlogCommentForm.d.ts +3 -0
  34. package/lib/components/features/blog/TMBlogCommentForm.js +42 -36
  35. package/lib/components/features/documents/TMDcmtBlog.d.ts +1 -0
  36. package/lib/components/features/documents/TMDcmtBlog.js +2 -1
  37. package/lib/components/features/documents/TMDcmtForm.d.ts +44 -34
  38. package/lib/components/features/documents/TMDcmtForm.js +365 -563
  39. package/lib/components/features/documents/TMDcmtFormActionButtons.d.ts +34 -0
  40. package/lib/components/features/documents/TMDcmtFormActionButtons.js +124 -0
  41. package/lib/components/features/documents/TMDcmtPreview.js +66 -13
  42. package/lib/components/features/documents/TMDcmtTasks.d.ts +3 -1
  43. package/lib/components/features/documents/TMDcmtTasks.js +2 -2
  44. package/lib/components/features/documents/TMFileUploader.d.ts +5 -0
  45. package/lib/components/features/documents/TMFileUploader.js +28 -6
  46. package/lib/components/features/documents/TMMasterDetailDcmts.js +31 -85
  47. package/lib/components/features/documents/TMRelationViewer.d.ts +7 -1
  48. package/lib/components/features/documents/TMRelationViewer.js +497 -111
  49. package/lib/components/features/search/TMSearch.d.ts +2 -2
  50. package/lib/components/features/search/TMSearch.js +3 -3
  51. package/lib/components/features/search/TMSearchQueryPanel.js +6 -6
  52. package/lib/components/features/search/TMSearchResult.d.ts +28 -25
  53. package/lib/components/features/search/TMSearchResult.js +445 -562
  54. package/lib/components/features/search/TMSignatureInfoContent.js +10 -6
  55. package/lib/components/features/search/TMTreeSelector.js +1 -1
  56. package/lib/components/features/tasks/TMTaskForm.d.ts +3 -1
  57. package/lib/components/features/tasks/TMTaskForm.js +61 -193
  58. package/lib/components/features/tasks/TMTaskFormUtils.d.ts +80 -0
  59. package/lib/components/features/tasks/TMTaskFormUtils.js +559 -0
  60. package/lib/components/features/tasks/TMTasksUtils.d.ts +3 -1
  61. package/lib/components/features/tasks/TMTasksUtils.js +46 -16
  62. package/lib/components/features/tasks/TMTasksUtilsView.d.ts +0 -7
  63. package/lib/components/features/tasks/TMTasksUtilsView.js +7 -14
  64. package/lib/components/features/tasks/TMTasksView.js +5 -3
  65. package/lib/components/features/workflow/TMWorkflowPopup.d.ts +20 -3
  66. package/lib/components/features/workflow/TMWorkflowPopup.js +21 -109
  67. package/lib/components/features/workflow/diagram/ConnectionComponent.d.ts +1 -0
  68. package/lib/components/features/workflow/diagram/ConnectionComponent.js +6 -2
  69. package/lib/components/features/workflow/diagram/DiagramItemForm.d.ts +2 -0
  70. package/lib/components/features/workflow/diagram/DiagramItemForm.js +32 -25
  71. package/lib/components/features/workflow/diagram/RecipientList.d.ts +3 -1
  72. package/lib/components/features/workflow/diagram/RecipientList.js +13 -9
  73. package/lib/components/features/workflow/diagram/WFDiagram.js +102 -5
  74. package/lib/components/features/workflow/diagram/workflowHelpers.js +31 -19
  75. package/lib/components/forms/Login/TMLoginForm.js +1 -1
  76. package/lib/components/forms/TMSaveForm.js +61 -13
  77. package/lib/components/grids/TMBlogsPost.js +8 -8
  78. package/lib/components/grids/TMBlogsPostUtils.js +2 -2
  79. package/lib/components/grids/TMRecentsManager.js +1 -1
  80. package/lib/components/index.d.ts +2 -0
  81. package/lib/components/index.js +2 -0
  82. package/lib/components/layout/panelManager/TMPanelManagerContainer.js +3 -2
  83. package/lib/components/pages/TMPage.js +4 -0
  84. package/lib/components/query/TMQueryEditor.d.ts +1 -0
  85. package/lib/components/query/TMQueryEditor.js +3 -3
  86. package/lib/components/viewers/TMMidViewer.js +2 -1
  87. package/lib/components/viewers/TMTidViewer.js +7 -3
  88. package/lib/helper/Enum_Localizator.js +5 -0
  89. package/lib/helper/GlobalStyles.js +3 -0
  90. package/lib/helper/SDKUI_Globals.d.ts +12 -0
  91. package/lib/helper/SDKUI_Globals.js +21 -1
  92. package/lib/helper/SDKUI_Localizator.d.ts +31 -7
  93. package/lib/helper/SDKUI_Localizator.js +286 -46
  94. package/lib/helper/TMIcons.d.ts +2 -1
  95. package/lib/helper/TMIcons.js +4 -1
  96. package/lib/helper/TMUtils.d.ts +33 -41
  97. package/lib/helper/TMUtils.js +157 -170
  98. package/lib/helper/checkinCheckoutManager.js +6 -2
  99. package/lib/helper/helpers.d.ts +6 -2
  100. package/lib/helper/helpers.js +24 -8
  101. package/lib/helper/index.d.ts +1 -0
  102. package/lib/helper/index.js +1 -0
  103. package/lib/helper/queryHelper.js +1 -1
  104. package/lib/hooks/useBetaFeatures.d.ts +1 -0
  105. package/lib/hooks/useBetaFeatures.js +41 -0
  106. package/lib/hooks/useCheckInOutOperations.d.ts +7 -6
  107. package/lib/hooks/useCheckInOutOperations.js +9 -16
  108. package/lib/hooks/useDataUserIdItem.js +2 -2
  109. package/lib/hooks/useDcmtOperations.d.ts +3 -2
  110. package/lib/hooks/useDcmtOperations.js +16 -4
  111. package/lib/hooks/useDocumentOperations.d.ts +139 -0
  112. package/lib/hooks/useDocumentOperations.js +1275 -0
  113. package/lib/hooks/useRelatedDocuments.d.ts +1 -1
  114. package/lib/hooks/useRelatedDocuments.js +64 -42
  115. package/lib/index.d.ts +1 -0
  116. package/lib/index.js +1 -0
  117. package/lib/services/platform_services.d.ts +1 -1
  118. package/lib/services/platform_services.js +4 -0
  119. package/lib/ts/types.d.ts +5 -1
  120. package/lib/ts/types.js +1 -0
  121. package/package.json +55 -55
  122. package/lib/components/features/search/TMSearchResultsMenuItems.d.ts +0 -11
  123. package/lib/components/features/search/TMSearchResultsMenuItems.js +0 -770
  124. package/lib/components/features/search/TMSignSettingsForm.d.ts +0 -9
  125. package/lib/components/features/search/TMSignSettingsForm.js +0 -621
@@ -1,8 +1,8 @@
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
3
  import styled from "styled-components";
4
- import { AccessLevels, DcmtTypeListCacheService, LayoutGroupBorderStyles, LayoutGroupOrientations, LayoutItemTypes, LayoutModes, MetadataDataDomains, MetadataDataTypes, SDK_Globals, SystemMIDsAsNumber, SystemTIDs, WorkItemMetadataNames } from '@topconsultnpm/sdk-ts';
5
- import { IconUndo, IconPencil, IconFunction, IconMenuVertical, IconDataList, SDKUI_Localizator, IconNull, stringIsNullOrEmpty, deepCompare, SDKUI_Globals, IconDcmtTypeSys, isApprovalWorkflowView } from "../../helper";
4
+ import { AccessLevels, AppModules, DcmtTypeListCacheService, LayoutGroupBorderStyles, LayoutGroupOrientations, LayoutItemTypes, LayoutModes, MetadataDataDomains, MetadataDataTypes, SDK_Globals, SystemMIDsAsNumber, SystemTIDs, WorkItemMetadataNames } from '@topconsultnpm/sdk-ts';
5
+ import { IconUndo, IconPencil, IconFunction, IconMenuVertical, IconDataList, SDKUI_Localizator, IconNull, stringIsNullOrEmpty, deepCompare, SDKUI_Globals, IconDcmtTypeSys, isApprovalWorkflowView, StyledTabItem, getAppModuleGradient } from "../../helper";
6
6
  import { TMColors } from "../../utils/theme";
7
7
  import TMButton from "../base/TMButton";
8
8
  import TMDropDownMenu from "../base/TMDropDownMenu";
@@ -14,6 +14,7 @@ import { ChronologyMIDs, DraftsMIDs, DSAttachsMIDs } from "../../ts";
14
14
  import { TMNothingToShow } from "../features/documents/TMDcmtPreview";
15
15
  import TMAccordion from "../base/TMAccordion";
16
16
  import TabPanel, { Item } from 'devextreme-react/tab-panel';
17
+ import { TMExceptionBoxManager } from "../base/TMPopUp";
17
18
  export var ShowCheckBoxesMode;
18
19
  (function (ShowCheckBoxesMode) {
19
20
  ShowCheckBoxesMode[ShowCheckBoxesMode["Never"] = 0] = "Never";
@@ -34,7 +35,6 @@ const TMMetadataValues = ({ showCheckBoxes = ShowCheckBoxesMode.Never, checkPerm
34
35
  const [selectedItem, setSelectedItem] = useState(undefined);
35
36
  const [prevMetadataValues, setPrevMetadataValues] = useState([]);
36
37
  const [inputMidsApplied, setInputMidsApplied] = useState(false);
37
- const [selectedIndex, setSelectedIndex] = useState(0);
38
38
  const onChangeHandler = useCallback((newValue, mid) => {
39
39
  let newValues = structuredClone(metadataValues);
40
40
  const item = newValues.find(value => value.mid === mid);
@@ -78,10 +78,20 @@ const TMMetadataValues = ({ showCheckBoxes = ShowCheckBoxesMode.Never, checkPerm
78
78
  setDynDataListsToBeRefreshed([]);
79
79
  return;
80
80
  }
81
- // Passiamo did = undefined, perché è già in cache
82
- DcmtTypeListCacheService.GetWithNotGrantedAsync(TID, undefined).then((resultDTD) => {
83
- setCurrentDTD(resultDTD);
84
- });
81
+ const fetchData = async () => {
82
+ try {
83
+ let resultDTD = await DcmtTypeListCacheService.GetAsync(TID);
84
+ if (!resultDTD) {
85
+ // Passiamo did = undefined, perché è già in cache
86
+ resultDTD = await DcmtTypeListCacheService.GetWithNotGrantedAsync(TID, undefined);
87
+ }
88
+ setCurrentDTD(resultDTD);
89
+ }
90
+ catch (error) {
91
+ TMExceptionBoxManager.show({ exception: error });
92
+ }
93
+ };
94
+ fetchData();
85
95
  }, [TID]);
86
96
  useEffect(() => {
87
97
  if (metadataValues.length <= 0)
@@ -165,7 +175,8 @@ const TMMetadataValues = ({ showCheckBoxes = ShowCheckBoxesMode.Never, checkPerm
165
175
  if (!d)
166
176
  return;
167
177
  let toBeRefreshed = [];
168
- let dynDlDataSource = await SDK_Globals.tmSession?.NewSearchEngine().GetDynDataListValuesAsync(tid, mid, layoutMode, qParams);
178
+ let dynDlDataSource = await SDK_Globals.tmSession?.NewSearchEngine().GetDynDataListValuesAsync(tid, mid, layoutMode, qParams)
179
+ .catch((err) => { TMExceptionBoxManager.show({ exception: err }); });
169
180
  if (!d.onValueChanged_DynDataListsToBeRefreshed)
170
181
  return;
171
182
  let row = dynDlDataSource?.dtdResult?.rows?.filter(o => o[d.selectItemForValue ?? 0] == value);
@@ -420,6 +431,55 @@ const TMMetadataValues = ({ showCheckBoxes = ShowCheckBoxesMode.Never, checkPerm
420
431
  });
421
432
  return (_jsx("div", { style: { width: '100%' }, children: chronologyData.length > 0 && chronologyData.map(item => renderMetadataItem(item, isReadOnly)) }));
422
433
  }, [metadataValues, showCheckBoxes, showNullValueCheckBoxes, isReadOnly, dynDataListsToBeRefreshed, validationItems, selectedMID, isOpenDistinctValues, openChooserBySingleClick, metadataValuesOrig]);
434
+ // Mappa TabLayoutItemID -> conteggio errori e dettagli per mostrare il badge sul tab
435
+ const tabErrorCountMap = useMemo(() => {
436
+ const map = new Map();
437
+ if (!layout || !layout.items || layout.items.length === 0 || !layout.showTab) {
438
+ return map;
439
+ }
440
+ // Trova i tab (LayoutGroup con parentID === 0 e orientation Vertical)
441
+ const tabGroups = layout.items.filter(item => item.type === LayoutItemTypes.LayoutGroup &&
442
+ item.parentID === 0 &&
443
+ item.lgd?.orientation === LayoutGroupOrientations.Vertical);
444
+ // Funzione ricorsiva per trovare tutti i MID figli di un tab
445
+ const findMidsInGroup = (parentID) => {
446
+ const mids = [];
447
+ const children = layout.items?.filter(item => item.parentID === parentID) || [];
448
+ for (const child of children) {
449
+ if (child.type === LayoutItemTypes.LayoutControlItem && child.lcid?.mid) {
450
+ mids.push(child.lcid.mid);
451
+ }
452
+ else if (child.type === LayoutItemTypes.LayoutGroup) {
453
+ mids.push(...findMidsInGroup(child.layoutItemID));
454
+ }
455
+ }
456
+ return mids;
457
+ };
458
+ // Per ogni tab, conta gli errori e raccoglie i dettagli
459
+ for (const tabGroup of tabGroups) {
460
+ const tabId = tabGroup.layoutItemID;
461
+ if (tabId === undefined)
462
+ continue;
463
+ const midsInTab = findMidsInGroup(tabId);
464
+ const errorDetails = [];
465
+ for (const mid of midsInTab) {
466
+ const md = metadataValues.find(m => m.mid === mid);
467
+ if (md) {
468
+ const validationItem = validationItems.find(v => v.PropertyName === md.md?.nameLoc);
469
+ if (validationItem) {
470
+ errorDetails.push({
471
+ fieldName: md.md?.nameLoc ?? '',
472
+ message: validationItem.Message ?? ''
473
+ });
474
+ }
475
+ }
476
+ }
477
+ if (errorDetails.length > 0) {
478
+ map.set(tabId, { count: errorDetails.length, details: errorDetails });
479
+ }
480
+ }
481
+ return map;
482
+ }, [layout, metadataValues, validationItems]);
423
483
  const layoutDsAttachs = useMemo(() => {
424
484
  const dsAttachsData = [];
425
485
  metadataValues.forEach(item => {
@@ -463,22 +523,56 @@ const TMMetadataValues = ({ showCheckBoxes = ShowCheckBoxesMode.Never, checkPerm
463
523
  }
464
524
  return layout.items?.filter(item => item.parentID === parentID) || [];
465
525
  };
466
- // Recursive function to render layout items with depth tracking for indentation
467
- // Prevent infinite recursion by tracking visited layoutItemIDs (handles malformed layouts where an item
468
- // may reference itself as a child or cycles exist).
526
+ /**
527
+ * Renderizza ricorsivamente l'albero del layout partendo dalla radice e scendendo verso i figli.
528
+ *
529
+ * Tipi gestiti:
530
+ * - LayoutRoot: elemento radice, renderizza i figli come tab (se showTab) o come contenitore semplice
531
+ * - LayoutGroup: contenitori con orientamento (Vertical/Horizontal) e stili bordo (NoBorder, Group, GroupBox, Tabbed)
532
+ * - LayoutControlItem: campi metadata terminali, recuperati tramite MID e passati a renderMetadataItem
533
+ * - SeparatorItem: linee di separazione orizzontali
534
+ *
535
+ * @param layoutItem - elemento del layout da renderizzare
536
+ * @param depth - profondità di annidamento per calcolare l'indentazione (default 0)
537
+ * @param visited - Set di ID già visitati per prevenire cicli infiniti in layout malformati
538
+ */
469
539
  const renderLayoutItem = (layoutItem, depth = 0, visited = new Set()) => {
470
540
  const id = layoutItem.layoutItemID ?? 0;
471
541
  if (visited.has(id))
472
542
  return null;
473
543
  visited.add(id);
544
+ // Helper: renderizza i children di un layout item
545
+ const renderChildren = (parentItem, childDepth) => {
546
+ const itemChildren = getChildren(parentItem.layoutItemID);
547
+ return itemChildren.map(child => (_jsx(React.Fragment, { children: renderLayoutItem(child, childDepth, visited) }, `child-${child.layoutItemID}`)));
548
+ };
474
549
  // Check if this is a LayoutRoot - just render its children
475
550
  if (layoutItem.type === LayoutItemTypes.LayoutRoot) {
476
551
  const children = getChildren(layoutItem.layoutItemID);
477
552
  if (layout.showTab) {
478
- return (_jsx(React.Fragment, { children: _jsx(TabPanel, { width: "100%", height: "100%", children: children.map(child => (_jsx(React.Fragment, { children: renderLayoutItem(child, depth, visited) }, `child-${child.layoutItemID}`))) }) }, `root-${layoutItem.layoutItemID}`));
553
+ // Per ogni figlio che è un LayoutGroup tab, costruisce i dati per il TabPanel
554
+ // Segna ogni LayoutGroup come visitato per prevenire cicli
555
+ const tabItems = [];
556
+ for (const child of children) {
557
+ const childId = child.layoutItemID ?? 0;
558
+ if (visited.has(childId))
559
+ continue;
560
+ visited.add(childId);
561
+ const childChildren = getChildren(child.layoutItemID);
562
+ const childContent = (_jsx("div", { style: { width: '100%' }, children: childChildren.map(grandChild => (_jsx(React.Fragment, { children: renderLayoutItem(grandChild, depth + 1, visited) }, `grandchild-${grandChild.layoutItemID}`))) }));
563
+ const errorData = tabErrorCountMap.get(childId);
564
+ tabItems.push({
565
+ layoutItemID: child.layoutItemID,
566
+ content: childContent,
567
+ title: (child.type === LayoutItemTypes.LayoutGroup && child.lgd?.caption) || `Tab ${child.layoutItemID}`,
568
+ errorCount: errorData?.count || 0,
569
+ errorDetails: errorData?.details || []
570
+ });
571
+ }
572
+ return (_jsx(React.Fragment, { children: _jsx(TMLayoutTabPanel, { tabItems: tabItems }) }, `root-${layoutItem.layoutItemID}`));
479
573
  }
480
574
  else {
481
- return (_jsx(React.Fragment, { children: children.map(child => (_jsx(React.Fragment, { children: renderLayoutItem(child, depth, visited) }, `child-${child.layoutItemID}`))) }, `root-${layoutItem.layoutItemID}`));
575
+ return (_jsx(React.Fragment, { children: renderChildren(layoutItem, depth) }, `root-${layoutItem.layoutItemID}`));
482
576
  }
483
577
  }
484
578
  // Check if this is a LayoutGroup
@@ -488,42 +582,55 @@ const TMMetadataValues = ({ showCheckBoxes = ShowCheckBoxesMode.Never, checkPerm
488
582
  const groupTitle = groupDescriptor.caption || `Group ${layoutItem.layoutItemID}`;
489
583
  const groupIsNoBorder = groupDescriptor.borderStyle == undefined || groupDescriptor.borderStyle == LayoutGroupBorderStyles.NoBorder || groupDescriptor.borderStyle == LayoutGroupBorderStyles.None;
490
584
  const isCollapsed = false; // LayoutGroupDescriptor doesn't have collapsed property
491
- //Layout Grou da trasformare in tab
492
- if (groupDescriptor.orientation == LayoutGroupOrientations.Vertical && layout.showTab && layoutItem.parentID === 0) {
493
- return (_jsx(Item, { title: groupTitle, children: _jsx("div", { style: { width: '100%' }, children: children.map(child => (_jsx(React.Fragment, { children: renderLayoutItem(child, depth + 1, visited) }, `child-${child.layoutItemID}`))) }) }, `group-tab-${layoutItem.layoutItemID}`));
585
+ const isVertical = groupDescriptor.orientation === LayoutGroupOrientations.Vertical;
586
+ const isHorizontal = groupDescriptor.orientation === LayoutGroupOrientations.Horizontal;
587
+ const nextDepth = depth + 1;
588
+ // Stile comune per gruppi con bordo e titolo
589
+ const borderedGroupStyle = (flexDir) => ({
590
+ position: 'relative',
591
+ border: '2px solid #CAD9EB',
592
+ borderRadius: '3px',
593
+ padding: '12px 6px 6px',
594
+ margin: '10px',
595
+ display: 'flex',
596
+ flexDirection: flexDir,
597
+ flexWrap: 'wrap',
598
+ gap: '3px'
599
+ });
600
+ const groupTitleElement = (_jsx("div", { style: { position: 'absolute', top: '-10px', left: '10px', padding: '0 8px', backgroundColor: '#fff', fontWeight: 600, fontSize: '1rem', color: TMColors.primaryColor }, children: groupTitle }));
601
+ // Layout Group da trasformare in tab - il rendering è già gestito da LayoutRoot
602
+ if (isVertical && layout.showTab && layoutItem.parentID === 0) {
603
+ return null;
494
604
  }
495
- if (groupIsNoBorder && groupDescriptor.orientation !== LayoutGroupOrientations.Horizontal && children.length == 0) {
496
- return (_jsx("br", {}));
605
+ // Gruppo vuoto senza bordo (non orizzontale) line break
606
+ if (groupIsNoBorder && !isHorizontal && children.length === 0) {
607
+ return _jsx("br", {});
497
608
  }
498
- if (!groupIsNoBorder && groupDescriptor.orientation === LayoutGroupOrientations.Horizontal && children.length > 0 && groupTitle.length > 0) {
499
- return (
500
- // <div key={`group-horizontal-${layoutItem.layoutItemID}`} style={{ display: 'flex', flexDirection: 'row', flexWrap: 'wrap', gap: '3px' }}>
501
- _jsxs("div", { style: { position: 'relative', border: '2px solid #CAD9EB', borderRadius: '3px', padding: '12px 6px 6px', margin: '10px', display: 'flex', flexDirection: 'row', flexWrap: 'wrap', gap: '3px' }, children: [_jsx("div", { style: { position: 'absolute', top: '-10px', left: '10px', padding: '0 8px', backgroundColor: '#fff', fontWeight: 600, fontSize: '1rem', color: TMColors.primaryColor, }, children: groupTitle }), children.map(child => (_jsx(React.Fragment, { children: renderLayoutItem(child, depth + 1, visited) }, `child-${child.layoutItemID}`))), " "] }, `group-horizontal-${layoutItem.layoutItemID}`)
502
- // </div>
503
- );
609
+ // Orizzontale con bordo, children e titolo
610
+ if (!groupIsNoBorder && isHorizontal && children.length > 0 && groupTitle.length > 0) {
611
+ return (_jsxs("div", { style: borderedGroupStyle('row'), children: [groupTitleElement, renderChildren(layoutItem, nextDepth)] }, `group-horizontal-${layoutItem.layoutItemID}`));
504
612
  }
505
- if (groupIsNoBorder && groupDescriptor.orientation === LayoutGroupOrientations.Vertical) {
506
- return (_jsx("div", { style: { width: '100%', border: 'none', padding: 0 }, children: children.map(child => (_jsx(React.Fragment, { children: renderLayoutItem(child, depth + 1, visited) }, `child-${child.layoutItemID}`))) }));
613
+ // Verticale senza bordo
614
+ if (groupIsNoBorder && isVertical) {
615
+ return (_jsx("div", { style: { width: '100%', border: 'none', padding: 0 }, children: renderChildren(layoutItem, nextDepth) }));
507
616
  }
508
- if (!groupIsNoBorder && groupDescriptor.orientation === LayoutGroupOrientations.Vertical) {
509
- if (groupDescriptor.borderStyle == LayoutGroupBorderStyles.Group) {
510
- return (_jsxs("div", { style: { position: 'relative', border: '2px solid #CAD9EB', borderRadius: '3px', padding: '12px 6px 6px', margin: '10px', display: 'flex', flexDirection: 'column', flexWrap: 'wrap', gap: '3px', }, children: [_jsx("div", { style: { position: 'absolute', top: '-10px', left: '10px', padding: '0 8px', backgroundColor: '#fff', fontWeight: 600, fontSize: '1rem', color: TMColors.primaryColor, }, children: groupTitle }), children.map(child => (_jsx(React.Fragment, { children: renderLayoutItem(child, depth + 1, visited) }, `child-${child.layoutItemID}`)))] }));
617
+ // Verticale con bordo
618
+ if (!groupIsNoBorder && isVertical) {
619
+ if (groupDescriptor.borderStyle === LayoutGroupBorderStyles.Group) {
620
+ return (_jsxs("div", { style: borderedGroupStyle('column'), children: [groupTitleElement, renderChildren(layoutItem, nextDepth)] }));
511
621
  }
512
- if (groupDescriptor.borderStyle == LayoutGroupBorderStyles.GroupBox || groupDescriptor.borderStyle == LayoutGroupBorderStyles.Tabbed) {
513
- return (_jsx(TMAccordion, { title: groupTitle, titleSize: "Small", children: children.map(child => (_jsx(React.Fragment, { children: renderLayoutItem(child, depth + 1, visited) }, `child-${child.layoutItemID}`))) }));
622
+ if (groupDescriptor.borderStyle === LayoutGroupBorderStyles.GroupBox || groupDescriptor.borderStyle === LayoutGroupBorderStyles.Tabbed) {
623
+ return (_jsx(TMAccordion, { title: groupTitle, titleSize: "Small", children: renderChildren(layoutItem, nextDepth) }));
514
624
  }
515
625
  }
516
- if (groupDescriptor.orientation === LayoutGroupOrientations.Horizontal) {
517
- return (_jsx("div", { style: { display: 'flex', flexDirection: 'row', flexWrap: 'wrap', gap: '3px' }, children: groupDescriptor.borderStyle == LayoutGroupBorderStyles.GroupBox || groupDescriptor.borderStyle == LayoutGroupBorderStyles.Tabbed ?
518
- _jsx(TMAccordion, { title: groupTitle, titleSize: "Small", children: children.map(child => (_jsx(React.Fragment, { children: renderLayoutItem(child, depth + 1, visited) }, `child-${child.layoutItemID}`))) }) :
519
- groupDescriptor.borderStyle == LayoutGroupBorderStyles.Group ?
520
- _jsxs("div", { style: { position: 'relative', border: '2px solid #CAD9EB', borderRadius: '3px', padding: '12px 6px 6px', margin: '10px', display: 'flex', flexDirection: 'column', flexWrap: 'wrap', gap: '3px', }, children: [_jsx("div", { style: { position: 'absolute', top: '-10px', left: '10px', padding: '0 8px', backgroundColor: '#fff', fontWeight: 600, fontSize: '1rem', color: TMColors.primaryColor, }, children: groupTitle }), children.map(child => (_jsx("div", { style: { flex: '1 1 0', minWidth: 0 }, children: renderLayoutItem(child, depth + 1, visited) }, child.layoutItemID)))] })
521
- :
522
- children.map(child => (_jsx("div", { style: { flex: '1 1 0', minWidth: 0 }, children: renderLayoutItem(child, depth + 1, visited) }, child.layoutItemID))) }, `group-horizontal-${layoutItem.layoutItemID}`));
626
+ // Orizzontale
627
+ if (isHorizontal) {
628
+ const renderHorizontalChildren = () => children.map(child => (_jsx("div", { style: { flex: '1 1 0', minWidth: 0 }, children: renderLayoutItem(child, nextDepth, visited) }, child.layoutItemID)));
629
+ return (_jsx("div", { style: { display: 'flex', flexDirection: 'row', flexWrap: 'wrap', gap: '3px' }, children: groupDescriptor.borderStyle === LayoutGroupBorderStyles.GroupBox || groupDescriptor.borderStyle === LayoutGroupBorderStyles.Tabbed ? (_jsx(TMAccordion, { title: groupTitle, titleSize: "Small", children: renderChildren(layoutItem, nextDepth) })) : groupDescriptor.borderStyle === LayoutGroupBorderStyles.Group ? (_jsxs("div", { style: borderedGroupStyle('column'), children: [groupTitleElement, renderHorizontalChildren()] })) : (renderHorizontalChildren()) }, `group-horizontal-${layoutItem.layoutItemID}`));
523
630
  }
524
- // Apply indentation only to subgroups (depth > 0), not to root groups
631
+ // Fallback: gruppo con accordion e indentazione
525
632
  const indentationPx = depth > 0 ? depth * 10 : 0;
526
- return (_jsx("div", { style: { paddingLeft: `${indentationPx}px` }, children: _jsx(TMAccordion, { title: groupTitle, defaultCollapsed: isCollapsed, titleSize: "Small", children: children.map(child => (_jsx(React.Fragment, { children: renderLayoutItem(child, depth + 1, visited) }, `child-${child.layoutItemID}`))) }) }, `group-wrapper-${layoutItem.layoutItemID}`));
633
+ return (_jsx("div", { style: { paddingLeft: `${indentationPx}px` }, children: _jsx(TMAccordion, { title: groupTitle, defaultCollapsed: isCollapsed, titleSize: "Small", children: renderChildren(layoutItem, nextDepth) }) }, `group-wrapper-${layoutItem.layoutItemID}`));
527
634
  }
528
635
  // Check if this is a LayoutControlItem (metadata field)
529
636
  else if (layoutItem.type === LayoutItemTypes.LayoutControlItem && layoutItem.lcid) {
@@ -557,7 +664,7 @@ const TMMetadataValues = ({ showCheckBoxes = ShowCheckBoxesMode.Never, checkPerm
557
664
  const visited = new Set();
558
665
  return rootItems.map(item => (_jsx(React.Fragment, { children: renderLayoutItem(item, 0, visited) }, `root-item-${item.layoutItemID}`)));
559
666
  })() }));
560
- }, [layout, metadataValues, showCheckBoxes, showNullValueCheckBoxes, isReadOnly, dynDataListsToBeRefreshed, validationItems, selectedMID, isOpenDistinctValues, openChooserBySingleClick, metadataValuesOrig]);
667
+ }, [layout, metadataValues, showCheckBoxes, showNullValueCheckBoxes, isReadOnly, dynDataListsToBeRefreshed, validationItems, selectedMID, isOpenDistinctValues, openChooserBySingleClick, metadataValuesOrig, tabErrorCountMap]);
561
668
  const renderForm = useMemo(() => {
562
669
  // Se currentDTD non è ancora stato caricato, non renderizzare nulla
563
670
  if (!currentDTD) {
@@ -609,3 +716,58 @@ const StyledSeparator = styled.hr `
609
716
  border: none;
610
717
  border-top: 1px solid #e0e0e0;
611
718
  `;
719
+ const StyledErrorBadge = styled.span `
720
+ display: inline-flex;
721
+ align-items: center;
722
+ justify-content: center;
723
+ min-width: 18px;
724
+ height: 18px;
725
+ padding: 0 5px;
726
+ border-radius: 9px;
727
+ background-color: #c62828;
728
+ color: white;
729
+ font-size: 0.75rem;
730
+ font-weight: bold;
731
+ line-height: 1;
732
+ margin-left: 6px;
733
+ `;
734
+ const TMLayoutTabPanel = React.memo(({ tabItems }) => {
735
+ const [activeTabIndex, setActiveTabIndex] = useState(0);
736
+ const handleSelectedIndexChange = useCallback((index) => {
737
+ setActiveTabIndex(index);
738
+ }, []);
739
+ return (_jsx(TabPanel, { width: "100%", height: "100%", animationEnabled: false, swipeEnabled: false, loop: false, showNavButtons: true, repaintChangesOnly: true, stylingMode: "primary", iconPosition: 'start', tabsPosition: 'top', selectedIndex: activeTabIndex, onSelectedIndexChange: handleSelectedIndexChange, children: tabItems.map((tabItem, index) => (_jsx(Item, { title: tabItem.title, tabRender: () => (_jsxs(StyledTabItem, { "$isSelected": activeTabIndex === index, "$activeGradient": getAppModuleGradient(SDK_Globals.tmSession?.SessionDescr?.appModuleID ?? AppModules.SURFER), children: [_jsx("span", { children: tabItem.title }), tabItem.errorCount !== undefined && tabItem.errorCount > 0 && (_jsx(TMTooltip, { content: _jsxs("div", { style: {
740
+ minWidth: '240px',
741
+ padding: '14px',
742
+ borderRadius: '10px',
743
+ background: '#ffffff',
744
+ boxShadow: '0 6px 16px rgba(0,0,0,0.08)',
745
+ border: '1px solid #e5e7eb',
746
+ color: '#1f2937',
747
+ fontFamily: 'sans-serif'
748
+ }, children: [_jsx("div", { style: {
749
+ fontWeight: 600,
750
+ textAlign: 'center',
751
+ fontSize: '1.05em',
752
+ marginBottom: '10px',
753
+ color: '#b91c1c'
754
+ }, children: tabItem.errorCount === 1 ? "1 campo non valido" : `${tabItem.errorCount} campi non validi` }), _jsx("div", { style: {
755
+ height: '1px',
756
+ background: '#e5e7eb',
757
+ marginBottom: '10px'
758
+ } }), _jsx("div", { style: { display: 'flex', flexDirection: 'column', gap: '10px' }, children: tabItem.errorDetails?.map((error, idx) => (_jsxs("div", { style: {
759
+ padding: '10px',
760
+ borderRadius: '8px',
761
+ background: '#fef2f2',
762
+ border: '1px solid #fecaca'
763
+ }, children: [_jsx("div", { style: {
764
+ fontWeight: 600,
765
+ fontSize: '0.95em',
766
+ marginBottom: '3px',
767
+ color: '#991b1b'
768
+ }, children: error.fieldName }), _jsx("div", { style: {
769
+ fontSize: '0.85em',
770
+ color: '#7f1d1d',
771
+ lineHeight: 1.4
772
+ }, children: error.message })] }, idx))) })] }), children: _jsx(StyledErrorBadge, { children: tabItem.errorCount > 99 ? '99+' : tabItem.errorCount }) }))] })), children: _jsx("div", { style: { width: '100%' }, children: tabItem.content }) }, `tab-${tabItem.layoutItemID}`))) }));
773
+ });
@@ -13,6 +13,7 @@ interface ITMTextArea extends ITMEditorBase {
13
13
  maxLength?: number;
14
14
  resize?: boolean;
15
15
  autoCalculateRows?: boolean;
16
+ fillHeight?: boolean;
16
17
  }
17
18
  declare const TMTextArea: React.FunctionComponent<ITMTextArea>;
18
19
  export default TMTextArea;
@@ -28,7 +28,7 @@ const StyledTextAreaEditorButton = styled.div `
28
28
  // Define the TMTextArea component
29
29
  const TMTextArea = (props) => {
30
30
  // Extract properties from the props object
31
- const { label = '', value = '', width = '100%', height = 'auto', autoFocus = false, showClearButton, validationItems = [], disabled = false, isModifiedWhen = false, fontSize = FontSize.defaultFontSize, elementStyle = {}, icon = null, labelPosition = 'left', readOnly = false, onValueChanged, onBlur, placeHolder, formulaItems = [], buttons = [], maxHeight = 'auto', rows, maxLength, resize = true, autoCalculateRows = true } = props;
31
+ const { label = '', value = '', width = '100%', height = 'auto', autoFocus = false, showClearButton, validationItems = [], disabled = false, isModifiedWhen = false, fontSize = FontSize.defaultFontSize, elementStyle = {}, icon = null, labelPosition = 'left', readOnly = false, onValueChanged, onBlur, placeHolder, formulaItems = [], buttons = [], maxHeight = 'auto', rows, maxLength, resize = true, autoCalculateRows = true, fillHeight = false } = props;
32
32
  // Reference to the textarea DOM element
33
33
  const inputRef = useRef(null);
34
34
  // Stores the textarea is focused
@@ -36,7 +36,7 @@ const TMTextArea = (props) => {
36
36
  // Stores the current value of the textarea
37
37
  const [currentValue, setCurrentValue] = useState(value);
38
38
  // Stores the calculated number of rows for the textarea
39
- const [calculatedRows, setCalculatedRows] = useState(rows ?? 1);
39
+ const [calculatedRows, setCalculatedRows] = useState(fillHeight ? 1 : (rows ?? 1));
40
40
  //Show chooserForm formulaItems
41
41
  const [showFormulaItemsChooser, setShowFormulaItemsChooser] = useState(false);
42
42
  const deviceType = useDeviceType();
@@ -148,8 +148,8 @@ const TMTextArea = (props) => {
148
148
  };
149
149
  // Renders the textarea
150
150
  const renderTextArea = () => {
151
- const textareaElement = _jsxs(_Fragment, { children: [_jsx(StyledTextareaEditor, { ref: inputRef, autoFocus: autoFocus, readOnly: readOnly, disabled: disabled, value: currentValue, placeholder: placeHolder, rows: calculatedRows, maxLength: maxLength, spellCheck: false, onFocus: () => setIsFocused(true), onBlur: (e) => { setIsFocused(false); if (currentValue != value)
152
- onBlur?.(currentValue); }, onChange: (e) => { setCurrentValue(e.target.value); onValueChanged?.(e); }, "$isMobile": deviceType === DeviceType.MOBILE, "$maxHeight": maxHeight, "$disabled": disabled, "$vil": validationItems, "$isModified": isModifiedWhen, "$fontSize": fontSize, "$width": width, "$resize": resize }), _jsxs("div", { style: { display: 'flex', flexDirection: 'row', justifyContent: 'flex-start', alignItems: 'center', position: 'absolute', right: '6px', top: calculatedRows === 1 ? (label.length > 0 ? '20px' : '7px') : (label.length > 0 ? '22px' : '7px'), pointerEvents: disabled ? 'none' : 'auto', opacity: disabled ? 0.4 : 1 }, children: [formulaItems.length > 0 &&
151
+ const textareaElement = _jsxs(_Fragment, { children: [_jsx(StyledTextareaEditor, { ref: inputRef, autoFocus: autoFocus, readOnly: readOnly, disabled: disabled, value: currentValue, placeholder: placeHolder, rows: fillHeight ? undefined : calculatedRows, maxLength: maxLength, spellCheck: false, onFocus: () => setIsFocused(true), onBlur: (e) => { setIsFocused(false); if (currentValue != value)
152
+ onBlur?.(currentValue); }, onChange: (e) => { setCurrentValue(e.target.value); onValueChanged?.(e); }, "$isMobile": deviceType === DeviceType.MOBILE, "$maxHeight": maxHeight, "$disabled": disabled, "$vil": validationItems, "$isModified": isModifiedWhen, "$fontSize": fontSize, "$width": width, "$resize": resize, style: fillHeight ? { flex: 1, height: 0 } : undefined }), _jsxs("div", { style: { display: 'flex', flexDirection: 'row', justifyContent: 'flex-start', alignItems: 'center', position: 'absolute', right: '6px', top: calculatedRows === 1 ? (label.length > 0 ? '20px' : '7px') : (label.length > 0 ? '22px' : '7px'), pointerEvents: disabled ? 'none' : 'auto', opacity: disabled ? 0.4 : 1 }, children: [formulaItems.length > 0 &&
153
153
  _jsx(StyledTextAreaEditorButton, { onClick: () => {
154
154
  setShowFormulaItemsChooser(true);
155
155
  }, children: _jsx(IconDataList, {}) }), showClearButton && currentValue &&
@@ -170,8 +170,8 @@ const TMTextArea = (props) => {
170
170
  };
171
171
  // Layout for the textarea with a left-aligned label
172
172
  const renderedLeftLabelTextArea = () => {
173
- return (_jsxs(TMLayoutContainer, { direction: 'horizontal', children: [icon && _jsx(TMLayoutItem, { width: '20px', children: _jsx(StyledEditorIcon, { "$disabled": disabled, "$vil": validationItems, "$isModified": isModifiedWhen, children: icon }) }), _jsx(TMLayoutItem, { children: _jsxs(StyledEditorContainer, { "$width": width, children: [label && _jsx(StyledEditorLabel, { "$isFocused": isFocused, "$labelPosition": labelPosition, "$disabled": disabled, children: label ?? '' }), renderTextArea()] }) })] }));
173
+ return (_jsxs(TMLayoutContainer, { direction: 'horizontal', children: [icon && _jsx(TMLayoutItem, { width: '20px', children: _jsx(StyledEditorIcon, { "$disabled": disabled, "$vil": validationItems, "$isModified": isModifiedWhen, children: icon }) }), _jsx(TMLayoutItem, { children: _jsxs(StyledEditorContainer, { "$width": width, style: fillHeight ? { height: '100%', display: 'flex', flexDirection: 'column' } : {}, children: [label && _jsx(StyledEditorLabel, { "$isFocused": isFocused, "$labelPosition": labelPosition, "$disabled": disabled, children: label ?? '' }), renderTextArea()] }) })] }));
174
174
  };
175
- return (_jsx("div", { style: elementStyle, children: renderedLeftLabelTextArea() }));
175
+ return (_jsx("div", { style: { ...elementStyle, ...(fillHeight ? { height: '100%' } : {}) }, children: renderedLeftLabelTextArea() }));
176
176
  };
177
177
  export default TMTextArea;
@@ -81,15 +81,14 @@ const TMTextBox = ({ autoFocus, maxLength, labelColor, precision, fromModal = fa
81
81
  }, [maxValue, minValue, currentValue, currentType]);
82
82
  // Handle autofocus behavior on mount
83
83
  useEffect(() => {
84
- if (autoFocus && inputRef.current) {
85
- if (fromModal) // utilizzato per i textBox derivanti da una Modal che non riescono a utilizzare l'autofocus
86
- setTimeout(() => {
87
- inputRef.current && inputRef.current.focus(); // Focus the input field
88
- }, 100);
89
- else
90
- inputRef.current.focus(); // Focus the input field
91
- }
92
- }, [autoFocus]); // This effect runs when the autoFocus prop changes
84
+ if (!autoFocus || !inputRef.current)
85
+ return;
86
+ const delay = fromModal ? 100 : 50;
87
+ const timeoutId = setTimeout(() => {
88
+ inputRef.current?.focus();
89
+ }, delay);
90
+ return () => clearTimeout(timeoutId);
91
+ }, [autoFocus, fromModal]); // This effect runs when the autoFocus or fromModal prop changes
93
92
  useEffect(() => {
94
93
  if (formulaItems && formulaItems.length > 0) {
95
94
  let menuItems = [];
@@ -278,7 +277,7 @@ const TMTextBox = ({ autoFocus, maxLength, labelColor, precision, fromModal = fa
278
277
  return 6 + (buttonCount * buttonWidth) + 8;
279
278
  }
280
279
  };
281
- return (_jsxs("div", { style: { width: '100%', height: 'fit-content' }, id: `text-${id}`, children: [_jsx(StyledEditor, { ref: inputRef, id: `text-${label}-${id}`, name: label, autoFocus: autoFocus, readOnly: readOnly, type: currentType, disabled: disabled, value: displayedValue, width: width || '100%', placeholder: placeHolder, maxLength: maxLength, autoComplete: 'off', spellCheck: false, onFocus: () => setIsFocused(true), onBlur: (e) => { setIsFocused(false); if (currentValue != value)
280
+ return (_jsxs("div", { style: { width: '100%', height: 'fit-content' }, id: `text-${id}`, children: [_jsx(StyledEditor, { ref: inputRef, onContextMenu: (e) => e.stopPropagation(), id: `text-${label}-${id}`, name: label, autoFocus: autoFocus, readOnly: readOnly, type: currentType, disabled: disabled, value: displayedValue, width: width || '100%', placeholder: placeHolder, maxLength: maxLength, autoComplete: 'off', spellCheck: false, onFocus: () => setIsFocused(true), onBlur: (e) => { setIsFocused(false); if (currentValue != value)
282
281
  onBlur?.(currentValue); }, onChange: handleInputChange, onKeyDown: (e) => {
283
282
  if (currentType === 'number') {
284
283
  if (!scale && (e.key == "." || e.key == ","))
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { HomeBlogPost, TaskDescriptor } from '@topconsultnpm/sdk-ts';
2
+ import { DcmtTypeDescriptor, HomeBlogPost, TaskDescriptor } from '@topconsultnpm/sdk-ts';
3
3
  interface ITMArchiveProps {
4
4
  inputFile?: File | null;
5
5
  inputMids?: Array<{
@@ -24,6 +24,8 @@ interface ITMArchiveProps {
24
24
  editTaskCallback?: (task: TaskDescriptor) => Promise<void>;
25
25
  handleNavigateToWGs?: (value: HomeBlogPost | number) => Promise<void>;
26
26
  handleNavigateToDossiers?: (value: HomeBlogPost | number) => Promise<void>;
27
+ openFileUploaderPdfEditor?: (fromDTD?: DcmtTypeDescriptor, file?: File | null, handleFile?: (file: File) => void) => void;
28
+ onScanRequest?: (onFileScanned: (file: File) => void) => void;
27
29
  }
28
30
  declare const TMArchive: React.FunctionComponent<ITMArchiveProps>;
29
31
  export default TMArchive;
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import React, { useEffect, useMemo, useState } from 'react';
3
3
  import Logo from '../../../assets/Toppy-generico.png';
4
- import { DcmtTypeListCacheService, LayoutModes, SDK_Localizator } from '@topconsultnpm/sdk-ts';
4
+ import { ArchiveConstraints, DcmtTypeListCacheService, LayoutModes, SDK_Localizator } from '@topconsultnpm/sdk-ts';
5
5
  import { IconTree, SDKUI_Globals, SDKUI_Localizator, IconRecentlyViewed, IconPreview, IconShow, IconBoard, IconDcmtTypeSys, removeMruTid, getMoreInfoTasksForDocument } from '../../../helper';
6
6
  import { useDeviceType, DeviceType } from '../../base/TMDeviceProvider';
7
7
  import TMLayoutContainer from '../../base/TMLayout';
@@ -12,7 +12,7 @@ import TMTreeSelector from '../search/TMTreeSelector';
12
12
  import TMPanel from '../../base/TMPanel';
13
13
  import { TMPanelManagerProvider, useTMPanelManagerContext } from '../../layout/panelManager/TMPanelManagerContext';
14
14
  import TMPanelManagerContainer from '../../layout/panelManager/TMPanelManagerContainer';
15
- const TMArchive = ({ onDcmtTypeSelect = undefined, inputTID, inputFile = null, connectorFileSave = undefined, onSavedAsyncCallback, inputMids = [], enableDragDropOverlay = false, passToSearch, isSharedArchive = false, inputDID = undefined, allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTaskCallback, editTaskCallback, handleNavigateToWGs, handleNavigateToDossiers }) => {
15
+ const TMArchive = ({ onDcmtTypeSelect = undefined, inputTID, inputFile = null, connectorFileSave = undefined, onSavedAsyncCallback, inputMids = [], enableDragDropOverlay = false, passToSearch, isSharedArchive = false, inputDID = undefined, allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTaskCallback, editTaskCallback, handleNavigateToWGs, handleNavigateToDossiers, openFileUploaderPdfEditor, onScanRequest }) => {
16
16
  const [currentTID, setCurrentTID] = useState(inputTID ?? 0);
17
17
  const [mruTIDs, setMruTIDs] = useState([]);
18
18
  const [currentMruTID, setCurrentMruTID] = useState(0);
@@ -77,7 +77,7 @@ const TMArchive = ({ onDcmtTypeSelect = undefined, inputTID, inputFile = null, c
77
77
  if (onDcmtTypeSelect)
78
78
  onDcmtTypeSelect(tidToUse);
79
79
  passToSearch(tidToUse, outputMids);
80
- } : undefined, isSharedDcmt: isSharedArchive, allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback, editTaskCallback: editTaskCallback, handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers, moreInfoTasks: getMoreInfoTasksForDocument(allTasks, currentTID, currentTID === inputTID ? inputDID : undefined) }, currentTID)
80
+ } : undefined, isSharedDcmt: isSharedArchive, allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback, editTaskCallback: editTaskCallback, handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers, moreInfoTasks: getMoreInfoTasksForDocument(allTasks, currentTID, currentTID === inputTID ? inputDID : undefined), openFileUploaderPdfEditor: openFileUploaderPdfEditor, onScanRequest: onScanRequest }, currentTID)
81
81
  :
82
82
  _jsx(TMPanel, { title: 'Archiviazione', allowMaximize: false, children: _jsxs(TMLayoutContainer, { gap: 30, alignItems: 'center', justifyContent: 'center', children: [_jsx(StyledToppyTextContainer, { children: _jsx(StyledToppyText, { children: SDKUI_Localizator.DcmtTypeSelect }) }), _jsx(StyledToppyImage, { src: Logo, alt: 'Toppy' })] }) }), [currentTID, deviceType, mruTIDs, inputFile, currentInputMids, enableDragDropOverlay, isSharedArchive, allTasks]);
83
83
  const allInitialPanelVisibility = {
@@ -145,49 +145,36 @@ const TMArchive = ({ onDcmtTypeSelect = undefined, inputTID, inputFile = null, c
145
145
  export default TMArchive;
146
146
  const TMTreeSelectorWrapper = ({ isMobile, isSharedArchive, onSelectedTIDChanged }) => {
147
147
  const { setPanelVisibilityById, toggleMaximize, setToolbarButtonVisibility, countVisibleLeafPanels } = useTMPanelManagerContext();
148
- return (_jsx(TMTreeSelector, { layoutMode: LayoutModes.Ark, onClosePanel: !isMobile && countVisibleLeafPanels() > 1 ? () => setPanelVisibilityById('tmTreeSelector', false) : undefined, allowMaximize: !isMobile && countVisibleLeafPanels() > 1, onMaximizePanel: !isMobile && countVisibleLeafPanels() > 1 ? () => toggleMaximize("tmTreeSelector") : undefined, onSelectedTIDChanged: (tid) => {
149
- onSelectedTIDChanged?.(tid);
150
- if (isMobile)
151
- setPanelVisibilityById('tmDcmtForm', true);
152
- else {
153
- setPanelVisibilityById('tmDcmtForm', true);
154
- if (!isSharedArchive) {
155
- setPanelVisibilityById('tmDcmtPreview', true);
156
- }
157
- }
158
- if (!isSharedArchive) {
159
- setToolbarButtonVisibility('tmDcmtPreview', true);
160
- }
161
- setToolbarButtonVisibility('tmDcmtForm', true);
162
- } }));
148
+ const updatePanelsVisibility = async (tid) => {
149
+ if (!tid)
150
+ return;
151
+ const dtd = await DcmtTypeListCacheService.GetAsync(tid);
152
+ const isOnlyMetadata = dtd?.archiveConstraint === ArchiveConstraints.OnlyMetadata;
153
+ const previewVisible = !isSharedArchive && !isOnlyMetadata;
154
+ setPanelVisibilityById('tmDcmtPreview', previewVisible);
155
+ setToolbarButtonVisibility('tmDcmtPreview', previewVisible);
156
+ setPanelVisibilityById('tmDcmtForm', true);
157
+ setToolbarButtonVisibility('tmDcmtForm', true);
158
+ };
159
+ return (_jsx(TMTreeSelector, { layoutMode: LayoutModes.Ark, onClosePanel: !isMobile && countVisibleLeafPanels() > 1 ? () => setPanelVisibilityById('tmTreeSelector', false) : undefined, allowMaximize: !isMobile && countVisibleLeafPanels() > 1, onMaximizePanel: !isMobile && countVisibleLeafPanels() > 1 ? () => toggleMaximize("tmTreeSelector") : undefined, onSelectedTIDChanged: async (tid) => { updatePanelsVisibility(tid); onSelectedTIDChanged?.(tid); } }));
163
160
  };
164
161
  const TMRecentsManagerWrapper = ({ mruTIDs, currentTID, currentMruTID, deviceType, isSharedArchive, onSelectedTID, onDeletedTID }) => {
165
162
  const { setPanelVisibilityById, setToolbarButtonVisibility } = useTMPanelManagerContext();
163
+ // This avoids unnecessary re-renders by only recalculating when deviceType changes.
164
+ let isMobile = useMemo(() => { return deviceType === DeviceType.MOBILE; }, [deviceType]);
165
+ const updatePanelsVisibility = async (tid) => {
166
+ if (!tid)
167
+ return;
168
+ const dtd = await DcmtTypeListCacheService.GetAsync(tid);
169
+ const isOnlyMetadata = dtd?.archiveConstraint === ArchiveConstraints.OnlyMetadata;
170
+ const previewVisible = !isSharedArchive && !isOnlyMetadata;
171
+ setPanelVisibilityById('tmDcmtPreview', previewVisible);
172
+ setToolbarButtonVisibility('tmDcmtPreview', previewVisible);
173
+ setPanelVisibilityById('tmDcmtForm', true);
174
+ setToolbarButtonVisibility('tmDcmtForm', true);
175
+ };
166
176
  useEffect(() => {
167
- if (currentTID) {
168
- setPanelVisibilityById('tmDcmtForm', true);
169
- if (!isSharedArchive) {
170
- setToolbarButtonVisibility('tmDcmtPreview', true);
171
- }
172
- setToolbarButtonVisibility('tmDcmtForm', true);
173
- }
174
- }, [currentTID, isSharedArchive]);
175
- return (_jsx(TMRecentsManager, { accessFilter: 'canArchive', mruTIDs: mruTIDs, currentMruTID: currentMruTID, deviceType: deviceType, onSelectedTID: (tid) => {
176
- onSelectedTID?.(tid);
177
- if (deviceType === DeviceType.MOBILE) {
178
- setPanelVisibilityById('tmDcmtForm', true);
179
- }
180
- else {
181
- setPanelVisibilityById('tmDcmtForm', true);
182
- if (!isSharedArchive) {
183
- setPanelVisibilityById('tmDcmtPreview', true);
184
- }
185
- }
186
- if (!isSharedArchive) {
187
- setToolbarButtonVisibility('tmDcmtPreview', true);
188
- }
189
- setToolbarButtonVisibility('tmDcmtForm', true);
190
- }, onDeletedTID: (tid) => {
191
- onDeletedTID?.(tid);
192
- } }));
177
+ updatePanelsVisibility(currentTID);
178
+ }, [currentTID, isSharedArchive, isMobile]);
179
+ return (_jsx(TMRecentsManager, { accessFilter: "canArchive", mruTIDs: mruTIDs, currentMruTID: currentMruTID, deviceType: deviceType, onSelectedTID: async (tid) => { await updatePanelsVisibility(tid); onSelectedTID?.(tid); }, onDeletedTID: onDeletedTID }));
193
180
  };
@@ -14,6 +14,9 @@ interface TMBlogCommentFormProps {
14
14
  onFilterCreated?: (predicate: (post: BlogPost) => boolean) => void;
15
15
  refreshCallback?: () => Promise<void>;
16
16
  isCommentRequired?: boolean;
17
+ maxLength?: number;
18
+ /** External save handler - when provided, bypasses internal engine logic */
19
+ onCustomSave?: (blogPost: BlogPost) => Promise<void>;
17
20
  }
18
21
  declare const TMBlogCommentForm: (props: TMBlogCommentFormProps) => import("react/jsx-runtime").JSX.Element;
19
22
  export default TMBlogCommentForm;