@topconsultnpm/sdkui-react 6.20.0-t2 → 6.20.0-t3

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 (45) hide show
  1. package/lib/components/base/TMPopUp.js +4 -0
  2. package/lib/components/base/TMTreeView.js +12 -8
  3. package/lib/components/choosers/TMDataListItemChooser.js +1 -1
  4. package/lib/components/choosers/TMDataListItemFields.js +1 -1
  5. package/lib/components/choosers/TMDataListItemPicker.d.ts +1 -0
  6. package/lib/components/choosers/TMDataListItemPicker.js +5 -1
  7. package/lib/components/choosers/TMUserChooser.js +1 -1
  8. package/lib/components/editors/TMMetadataValues.js +200 -40
  9. package/lib/components/editors/TMTextArea.d.ts +1 -0
  10. package/lib/components/editors/TMTextArea.js +6 -6
  11. package/lib/components/features/archive/TMArchive.d.ts +1 -0
  12. package/lib/components/features/archive/TMArchive.js +2 -2
  13. package/lib/components/features/documents/TMDcmtForm.d.ts +1 -0
  14. package/lib/components/features/documents/TMDcmtForm.js +16 -7
  15. package/lib/components/features/documents/TMFileUploader.d.ts +2 -0
  16. package/lib/components/features/documents/TMFileUploader.js +16 -8
  17. package/lib/components/features/documents/TMMasterDetailDcmts.js +25 -63
  18. package/lib/components/features/documents/TMRelationViewer.js +109 -40
  19. package/lib/components/features/search/TMSearchQueryPanel.js +3 -3
  20. package/lib/components/features/search/TMSearchResult.js +5 -13
  21. package/lib/components/features/search/TMSearchResultsMenuItems.d.ts +1 -1
  22. package/lib/components/features/search/TMSearchResultsMenuItems.js +4 -16
  23. package/lib/components/features/search/TMSignatureInfoContent.js +10 -6
  24. package/lib/components/features/search/TMTreeSelector.js +1 -1
  25. package/lib/components/features/tasks/TMTaskFormUtils.js +1 -1
  26. package/lib/components/features/workflow/TMWorkflowPopup.js +9 -19
  27. package/lib/components/features/workflow/diagram/DiagramItemForm.d.ts +2 -0
  28. package/lib/components/features/workflow/diagram/DiagramItemForm.js +32 -25
  29. package/lib/components/features/workflow/diagram/RecipientList.d.ts +3 -1
  30. package/lib/components/features/workflow/diagram/RecipientList.js +13 -9
  31. package/lib/components/features/workflow/diagram/WFDiagram.js +29 -2
  32. package/lib/components/features/workflow/diagram/workflowHelpers.js +31 -19
  33. package/lib/components/grids/TMRecentsManager.js +1 -1
  34. package/lib/components/viewers/TMMidViewer.js +2 -1
  35. package/lib/components/viewers/TMTidViewer.js +2 -1
  36. package/lib/helper/SDKUI_Globals.d.ts +4 -0
  37. package/lib/helper/SDKUI_Globals.js +9 -1
  38. package/lib/helper/SDKUI_Localizator.d.ts +12 -4
  39. package/lib/helper/SDKUI_Localizator.js +104 -24
  40. package/lib/helper/TMUtils.d.ts +9 -41
  41. package/lib/helper/TMUtils.js +79 -167
  42. package/lib/hooks/useDataUserIdItem.js +2 -2
  43. package/package.json +2 -2
  44. package/lib/components/features/search/TMSignSettingsForm.d.ts +0 -9
  45. package/lib/components/features/search/TMSignSettingsForm.js +0 -621
@@ -258,6 +258,10 @@ const TMMessageBox = ({ resizable = false, onButtonClick, title = 'TopMedia', me
258
258
  const el = document.getElementById('tm-messagebox-wrapper');
259
259
  if (el)
260
260
  el.style.zIndex = '20000';
261
+ // Blocca traduzione sul titolo
262
+ const titleEl = el?.querySelector('.dx-popup-title');
263
+ if (titleEl)
264
+ titleEl.setAttribute('translate', 'no');
261
265
  }, onResizeEnd: handleResizeEnd, wrapperAttr: { id: 'tm-messagebox-wrapper' }, children: _jsx(ResponsiveMessageBody, { message: message, isMobile: isMobile, MessageToolbar: MessageToolbar, showToppy: showToppy }) }));
262
266
  };
263
267
  const TMExceptionBox = ({ resizable = false, exception, title = `${SDK_Globals.appModule} v. ${SDK_Globals.appVersion}`, onClose }) => {
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useCallback, useEffect, useRef } from 'react';
3
3
  import styled from 'styled-components';
4
- import { IconChevronDown, IconChevronRight, SDKUI_Localizator } from '../../helper';
4
+ import { IconArrowLeft, IconArrowRight, IconChevronDown, IconChevronRight, SDKUI_Localizator } from '../../helper';
5
5
  import TMButton from './TMButton';
6
6
  const TMTreeView = ({ dataSource = [], focusedItem, selectedItems = [], allowMultipleSelection, onDataChanged, calculateItemsForNode, itemRender, onNodeUpdate, onFocusedItemChanged, onSelectionChanged, shouldDelayFocusOnEvent, autoSelectChildren = true, itemsPerPage = 100, showLoadMoreButton = true }) => {
7
7
  useEffect(() => {
@@ -350,7 +350,7 @@ const TMTreeView = ({ dataSource = [], focusedItem, selectedItems = [], allowMul
350
350
  if (input) {
351
351
  input.indeterminate = isIndeterminate(node);
352
352
  }
353
- } })), _jsx("div", { style: { display: 'flex', alignItems: 'center', flex: 1, minWidth: 0 }, onClick: (e) => { handleNodeClick(node, e); }, children: itemRender(node) })] }), node.expanded && node.items && (_jsxs("div", { style: { paddingLeft: 20, width: '100%' }, children: [renderTree(getVisibleItems(node)), needsPagination(node) && (_jsxs(StyledStickyPaginator, { children: [_jsx(TMButton, { onClick: () => handlePageChange(node.key, (node.currentPage ?? 0) - 1), showTooltip: false, caption: "\u25C4", disabled: (node.currentPage ?? 0) <= 0 }), _jsx("span", { style: { fontSize: '12px', whiteSpace: 'nowrap', fontWeight: 500, overflow: 'hidden', textOverflow: 'ellipsis', minWidth: 0, color: 'white' }, children: SDKUI_Localizator.PaginationInfo.replaceParams((node.currentPage ?? 0) + 1, getTotalPages(node), node.items?.length ?? 0) }), _jsx(TMButton, { onClick: () => handlePageChange(node.key, (node.currentPage ?? 0) + 1), showTooltip: false, caption: "\u25BA", disabled: (node.currentPage ?? 0) >= getTotalPages(node) - 1 })] }))] }))] }, node.key)));
353
+ } })), _jsx("div", { style: { display: 'flex', alignItems: 'center', flex: 1, minWidth: 0 }, onClick: (e) => { handleNodeClick(node, e); }, children: itemRender(node) })] }), node.expanded && node.items && (_jsxs("div", { style: { paddingLeft: 20, width: '100%' }, children: [renderTree(getVisibleItems(node)), needsPagination(node) && (_jsxs(StyledStickyPaginator, { children: [_jsx(TMButton, { btnStyle: 'icon', onClick: () => handlePageChange(node.key, (node.currentPage ?? 0) - 1), showTooltip: false, caption: "\u25C4", icon: _jsx(IconArrowLeft, { color: 'white' }), disabled: (node.currentPage ?? 0) <= 0 }), _jsx("span", { style: { fontSize: '11px', whiteSpace: 'nowrap', fontWeight: 500, overflow: 'hidden', textOverflow: 'ellipsis', minWidth: 0, color: 'white' }, children: SDKUI_Localizator.PaginationInfo.replaceParams((node.currentPage ?? 0) + 1, getTotalPages(node), node.items?.length ?? 0) }), _jsx(TMButton, { btnStyle: 'icon', onClick: () => handlePageChange(node.key, (node.currentPage ?? 0) + 1), showTooltip: false, caption: "\u25BA", icon: _jsx(IconArrowRight, { color: 'white' }), disabled: (node.currentPage ?? 0) >= getTotalPages(node) - 1 })] }))] }))] }, node.key)));
354
354
  }, [handleNodeClick, handleNodeToggle, handleCheckboxChange, focusedItem, selectedItems, allowMultipleSelection, getVisibleItems, needsPagination, handlePageChange, getTotalPages]);
355
355
  return (_jsx("div", { style: { height: '100%', width: '100%', overflowY: 'auto', overflowX: 'hidden', padding: '0px 5px 2px 2px' }, children: renderTree(dataSource) }));
356
356
  };
@@ -378,19 +378,23 @@ export const StyledStickyPaginator = styled.div `
378
378
  display: flex;
379
379
  align-items: center;
380
380
  justify-content: center;
381
- gap: 8px;
382
- margin: 8px 0;
383
- padding: 8px 12px;
381
+ width: fit-content;
382
+ margin: 3px auto;
383
+ gap: 15px;
384
+ padding: 4px 10px;
384
385
  background: oklch(from var(--dx-color-primary) l c h / .85);
385
386
  border: 1px solid oklch(from var(--dx-color-primary) l c h / .9);
386
- border-radius: 6px;
387
- box-shadow: 0 -2px 8px oklch(from var(--dx-color-primary) l c h / .15);
387
+ border-radius: 3px;
388
+ box-shadow: 0 -1px 4px oklch(from var(--dx-color-primary) l c h / .15);
388
389
  transition: all 0.2s ease;
389
390
  min-width: 0;
390
391
  z-index: 10;
391
392
 
392
393
  & > button {
393
394
  flex-shrink: 0;
395
+ min-width: 24px !important;
396
+ min-height: 20px !important;
397
+ padding: 2px 6px !important;
394
398
  }
395
399
 
396
400
  & > span {
@@ -401,6 +405,6 @@ export const StyledStickyPaginator = styled.div `
401
405
  &:hover {
402
406
  background: oklch(from var(--dx-color-primary) l c h / .95);
403
407
  border-color: oklch(from var(--dx-color-primary) l c h / 1);
404
- box-shadow: 0 -2px 12px oklch(from var(--dx-color-primary) l c h / .2);
408
+ box-shadow: 0 -1px 6px oklch(from var(--dx-color-primary) l c h / .2);
405
409
  }
406
410
  `;
@@ -31,7 +31,7 @@ const cellRenderIcon = (data) => _jsx(TMImageLibrary, { imageID: data.data?.imag
31
31
  export const TMDataListItemChooserForm = (props) => {
32
32
  const dataColumns = useMemo(() => {
33
33
  return [
34
- { dataField: 'value', caption: SDKUI_Localizator.Value },
34
+ { dataField: 'value', caption: SDKUI_Localizator.Value, visible: false },
35
35
  { dataField: 'name', caption: SDKUI_Localizator.Description }
36
36
  ];
37
37
  }, []);
@@ -56,6 +56,6 @@ const TMDataListItemFields = ({ item, originalItem, onItemChanged, validationIte
56
56
  Object.assign(clone, item);
57
57
  onItemChanged(clone);
58
58
  };
59
- return (_jsxs(FieldsContainer, { children: [_jsx(TMTextBox, { label: SDKUI_Localizator.Value, value: item.value, isModifiedWhen: (item.value || '') != (originalItem?.value || ''), validationItems: validationItems.filter(o => o.PropertyName === "value"), readOnly: readOnly, onValueChanged: handleValueChange }), _jsx(TMLocalizedTextBox, { label: SDKUI_Localizator.Description, value: item.name, isModifiedWhen: (item.name || '') != (originalItem?.name || ''), validationItems: validationItems.filter(o => o.PropertyName === "itemName"), readOnly: readOnly, value_IT: item.namesLoc?.it_IT, value_EN: item.namesLoc?.en_US, value_FR: item.namesLoc?.fr_FR, value_PT: item.namesLoc?.pt_PT, value_ES: item.namesLoc?.es_ES, value_DE: item.namesLoc?.de_DE, onValueChanged: handleLocalizedNameChange }), _jsx(TMImageIDChooser, { elementStyle: { marginBottom: '10px' }, label: "Immagine", value: item.imageID, isModifiedWhen: (item.imageID || '') != (originalItem?.imageID || ''), validationItems: validationItems.filter(o => o.PropertyName === "imageID"), readOnly: readOnly, onValueChanged: handleImageIDChange })] }));
59
+ return (_jsxs(FieldsContainer, { children: [_jsx(TMTextBox, { label: SDKUI_Localizator.Value, value: item.value, isModifiedWhen: (item.value || '') != (originalItem?.value || ''), validationItems: validationItems.filter(o => o.PropertyName === "value"), readOnly: readOnly, autoFocus: true, onValueChanged: handleValueChange }), _jsx(TMLocalizedTextBox, { label: SDKUI_Localizator.Description, value: item.name, isModifiedWhen: (item.name || '') != (originalItem?.name || ''), validationItems: validationItems.filter(o => o.PropertyName === "itemName"), readOnly: readOnly, value_IT: item.namesLoc?.it_IT, value_EN: item.namesLoc?.en_US, value_FR: item.namesLoc?.fr_FR, value_PT: item.namesLoc?.pt_PT, value_ES: item.namesLoc?.es_ES, value_DE: item.namesLoc?.de_DE, onValueChanged: handleLocalizedNameChange }), _jsx(TMImageIDChooser, { elementStyle: { marginBottom: '10px' }, label: "Immagine", value: item.imageID, isModifiedWhen: (item.imageID || '') != (originalItem?.imageID || ''), validationItems: validationItems.filter(o => o.PropertyName === "imageID"), readOnly: readOnly, onValueChanged: handleImageIDChange })] }));
60
60
  };
61
61
  export default TMDataListItemFields;
@@ -4,6 +4,7 @@ interface TMDataListItemPickerProps {
4
4
  dataListID: number | undefined;
5
5
  selectedValue: string | undefined;
6
6
  onItemSelect: (item: DataListItemDescriptor) => void;
7
+ onItemEdited?: (originalItem: DataListItemDescriptor, editedItem: DataListItemDescriptor) => void;
7
8
  allowEdit?: boolean;
8
9
  }
9
10
  declare const TMDataListItemPicker: React.FC<TMDataListItemPickerProps>;
@@ -128,7 +128,7 @@ const Label = styled.div `
128
128
  font-weight: bold;
129
129
  margin-bottom: 5px;
130
130
  `;
131
- const TMDataListItemPicker = ({ dataListID, selectedValue, onItemSelect, allowEdit = false }) => {
131
+ const TMDataListItemPicker = ({ dataListID, selectedValue, onItemSelect, onItemEdited, allowEdit = false }) => {
132
132
  const [dataList, setDataList] = useState(undefined);
133
133
  const [items, setItems] = useState([]);
134
134
  const [loading, setLoading] = useState(true);
@@ -194,6 +194,10 @@ const TMDataListItemPicker = ({ dataListID, selectedValue, onItemSelect, allowEd
194
194
  DataListCacheService.Remove();
195
195
  // Ricarica i dati dalla cache (che richiamerà il server)
196
196
  await loadDataList(false);
197
+ // Notifica il parent se un item esistente è stato modificato
198
+ if (!isCreating && editingItem) {
199
+ onItemEdited?.(editingItem, newItem);
200
+ }
197
201
  handleCloseDialog();
198
202
  }
199
203
  catch (error) {
@@ -100,7 +100,7 @@ export const TMUserTooltip = ({ ud, children }) => {
100
100
  .filter(Boolean)
101
101
  .join('\n');
102
102
  };
103
- return (_jsx("div", { title: buildTitle(ud), children: children }));
103
+ return (_jsx("span", { title: buildTitle(ud), style: { display: 'inline-flex', alignItems: 'center' }, children: children }));
104
104
  };
105
105
  const getCompleteUserName = (domain, name) => {
106
106
  if (!name)
@@ -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";
@@ -35,7 +35,6 @@ const TMMetadataValues = ({ showCheckBoxes = ShowCheckBoxesMode.Never, checkPerm
35
35
  const [selectedItem, setSelectedItem] = useState(undefined);
36
36
  const [prevMetadataValues, setPrevMetadataValues] = useState([]);
37
37
  const [inputMidsApplied, setInputMidsApplied] = useState(false);
38
- const [selectedIndex, setSelectedIndex] = useState(0);
39
38
  const onChangeHandler = useCallback((newValue, mid) => {
40
39
  let newValues = structuredClone(metadataValues);
41
40
  const item = newValues.find(value => value.mid === mid);
@@ -79,10 +78,20 @@ const TMMetadataValues = ({ showCheckBoxes = ShowCheckBoxesMode.Never, checkPerm
79
78
  setDynDataListsToBeRefreshed([]);
80
79
  return;
81
80
  }
82
- // Passiamo did = undefined, perché è già in cache
83
- DcmtTypeListCacheService.GetWithNotGrantedAsync(TID, undefined).then((resultDTD) => {
84
- setCurrentDTD(resultDTD);
85
- });
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();
86
95
  }, [TID]);
87
96
  useEffect(() => {
88
97
  if (metadataValues.length <= 0)
@@ -422,6 +431,55 @@ const TMMetadataValues = ({ showCheckBoxes = ShowCheckBoxesMode.Never, checkPerm
422
431
  });
423
432
  return (_jsx("div", { style: { width: '100%' }, children: chronologyData.length > 0 && chronologyData.map(item => renderMetadataItem(item, isReadOnly)) }));
424
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]);
425
483
  const layoutDsAttachs = useMemo(() => {
426
484
  const dsAttachsData = [];
427
485
  metadataValues.forEach(item => {
@@ -465,22 +523,56 @@ const TMMetadataValues = ({ showCheckBoxes = ShowCheckBoxesMode.Never, checkPerm
465
523
  }
466
524
  return layout.items?.filter(item => item.parentID === parentID) || [];
467
525
  };
468
- // Recursive function to render layout items with depth tracking for indentation
469
- // Prevent infinite recursion by tracking visited layoutItemIDs (handles malformed layouts where an item
470
- // 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
+ */
471
539
  const renderLayoutItem = (layoutItem, depth = 0, visited = new Set()) => {
472
540
  const id = layoutItem.layoutItemID ?? 0;
473
541
  if (visited.has(id))
474
542
  return null;
475
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
+ };
476
549
  // Check if this is a LayoutRoot - just render its children
477
550
  if (layoutItem.type === LayoutItemTypes.LayoutRoot) {
478
551
  const children = getChildren(layoutItem.layoutItemID);
479
552
  if (layout.showTab) {
480
- 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}`));
481
573
  }
482
574
  else {
483
- 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}`));
484
576
  }
485
577
  }
486
578
  // Check if this is a LayoutGroup
@@ -490,42 +582,55 @@ const TMMetadataValues = ({ showCheckBoxes = ShowCheckBoxesMode.Never, checkPerm
490
582
  const groupTitle = groupDescriptor.caption || `Group ${layoutItem.layoutItemID}`;
491
583
  const groupIsNoBorder = groupDescriptor.borderStyle == undefined || groupDescriptor.borderStyle == LayoutGroupBorderStyles.NoBorder || groupDescriptor.borderStyle == LayoutGroupBorderStyles.None;
492
584
  const isCollapsed = false; // LayoutGroupDescriptor doesn't have collapsed property
493
- //Layout Grou da trasformare in tab
494
- if (groupDescriptor.orientation == LayoutGroupOrientations.Vertical && layout.showTab && layoutItem.parentID === 0) {
495
- 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;
496
604
  }
497
- if (groupIsNoBorder && groupDescriptor.orientation !== LayoutGroupOrientations.Horizontal && children.length == 0) {
498
- return (_jsx("br", {}));
605
+ // Gruppo vuoto senza bordo (non orizzontale) line break
606
+ if (groupIsNoBorder && !isHorizontal && children.length === 0) {
607
+ return _jsx("br", {});
499
608
  }
500
- if (!groupIsNoBorder && groupDescriptor.orientation === LayoutGroupOrientations.Horizontal && children.length > 0 && groupTitle.length > 0) {
501
- return (
502
- // <div key={`group-horizontal-${layoutItem.layoutItemID}`} style={{ display: 'flex', flexDirection: 'row', flexWrap: 'wrap', gap: '3px' }}>
503
- _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}`)
504
- // </div>
505
- );
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}`));
506
612
  }
507
- if (groupIsNoBorder && groupDescriptor.orientation === LayoutGroupOrientations.Vertical) {
508
- 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) }));
509
616
  }
510
- if (!groupIsNoBorder && groupDescriptor.orientation === LayoutGroupOrientations.Vertical) {
511
- if (groupDescriptor.borderStyle == LayoutGroupBorderStyles.Group) {
512
- 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)] }));
513
621
  }
514
- if (groupDescriptor.borderStyle == LayoutGroupBorderStyles.GroupBox || groupDescriptor.borderStyle == LayoutGroupBorderStyles.Tabbed) {
515
- 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) }));
516
624
  }
517
625
  }
518
- if (groupDescriptor.orientation === LayoutGroupOrientations.Horizontal) {
519
- return (_jsx("div", { style: { display: 'flex', flexDirection: 'row', flexWrap: 'wrap', gap: '3px' }, children: groupDescriptor.borderStyle == LayoutGroupBorderStyles.GroupBox || groupDescriptor.borderStyle == LayoutGroupBorderStyles.Tabbed ?
520
- _jsx(TMAccordion, { title: groupTitle, titleSize: "Small", children: children.map(child => (_jsx(React.Fragment, { children: renderLayoutItem(child, depth + 1, visited) }, `child-${child.layoutItemID}`))) }) :
521
- groupDescriptor.borderStyle == LayoutGroupBorderStyles.Group ?
522
- _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)))] })
523
- :
524
- 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}`));
525
630
  }
526
- // Apply indentation only to subgroups (depth > 0), not to root groups
631
+ // Fallback: gruppo con accordion e indentazione
527
632
  const indentationPx = depth > 0 ? depth * 10 : 0;
528
- 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}`));
529
634
  }
530
635
  // Check if this is a LayoutControlItem (metadata field)
531
636
  else if (layoutItem.type === LayoutItemTypes.LayoutControlItem && layoutItem.lcid) {
@@ -559,7 +664,7 @@ const TMMetadataValues = ({ showCheckBoxes = ShowCheckBoxesMode.Never, checkPerm
559
664
  const visited = new Set();
560
665
  return rootItems.map(item => (_jsx(React.Fragment, { children: renderLayoutItem(item, 0, visited) }, `root-item-${item.layoutItemID}`)));
561
666
  })() }));
562
- }, [layout, metadataValues, showCheckBoxes, showNullValueCheckBoxes, isReadOnly, dynDataListsToBeRefreshed, validationItems, selectedMID, isOpenDistinctValues, openChooserBySingleClick, metadataValuesOrig]);
667
+ }, [layout, metadataValues, showCheckBoxes, showNullValueCheckBoxes, isReadOnly, dynDataListsToBeRefreshed, validationItems, selectedMID, isOpenDistinctValues, openChooserBySingleClick, metadataValuesOrig, tabErrorCountMap]);
563
668
  const renderForm = useMemo(() => {
564
669
  // Se currentDTD non è ancora stato caricato, non renderizzare nulla
565
670
  if (!currentDTD) {
@@ -611,3 +716,58 @@ const StyledSeparator = styled.hr `
611
716
  border: none;
612
717
  border-top: 1px solid #e0e0e0;
613
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;
@@ -25,6 +25,7 @@ interface ITMArchiveProps {
25
25
  handleNavigateToWGs?: (value: HomeBlogPost | number) => Promise<void>;
26
26
  handleNavigateToDossiers?: (value: HomeBlogPost | number) => Promise<void>;
27
27
  openPdfEditor?: (fromDTD?: DcmtTypeDescriptor, file?: File | null, handleFile?: (file: File) => void) => void;
28
+ onScanRequest?: (onFileScanned: (file: File) => void) => void;
28
29
  }
29
30
  declare const TMArchive: React.FunctionComponent<ITMArchiveProps>;
30
31
  export default TMArchive;
@@ -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, openPdfEditor }) => {
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, openPdfEditor, 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), openPdfEditor: openPdfEditor }, 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), openPdfEditor: openPdfEditor, 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 = {
@@ -62,6 +62,7 @@ interface ITMDcmtFormProps {
62
62
  onOpenS4TViewerRequest?: (dcmtInfo: Array<DcmtInfo>, onRefreshSearchAsync?: (() => Promise<void>)) => void;
63
63
  s4TViewerDialogComponent?: React.ReactNode;
64
64
  enableDragDropOverlay?: boolean;
65
+ onScanRequest?: (onFileScanned: (file: File) => void) => void;
65
66
  passToSearch?: (outputMids: Array<{
66
67
  mid: number;
67
68
  value: string;