@topconsultnpm/sdkui-react 6.20.0-dev3.12 → 6.20.0-dev3.14

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.
@@ -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
  }, []);
@@ -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);
@@ -422,6 +421,55 @@ const TMMetadataValues = ({ showCheckBoxes = ShowCheckBoxesMode.Never, checkPerm
422
421
  });
423
422
  return (_jsx("div", { style: { width: '100%' }, children: chronologyData.length > 0 && chronologyData.map(item => renderMetadataItem(item, isReadOnly)) }));
424
423
  }, [metadataValues, showCheckBoxes, showNullValueCheckBoxes, isReadOnly, dynDataListsToBeRefreshed, validationItems, selectedMID, isOpenDistinctValues, openChooserBySingleClick, metadataValuesOrig]);
424
+ // Mappa TabLayoutItemID -> conteggio errori e dettagli per mostrare il badge sul tab
425
+ const tabErrorCountMap = useMemo(() => {
426
+ const map = new Map();
427
+ if (!layout || !layout.items || layout.items.length === 0 || !layout.showTab) {
428
+ return map;
429
+ }
430
+ // Trova i tab (LayoutGroup con parentID === 0 e orientation Vertical)
431
+ const tabGroups = layout.items.filter(item => item.type === LayoutItemTypes.LayoutGroup &&
432
+ item.parentID === 0 &&
433
+ item.lgd?.orientation === LayoutGroupOrientations.Vertical);
434
+ // Funzione ricorsiva per trovare tutti i MID figli di un tab
435
+ const findMidsInGroup = (parentID) => {
436
+ const mids = [];
437
+ const children = layout.items?.filter(item => item.parentID === parentID) || [];
438
+ for (const child of children) {
439
+ if (child.type === LayoutItemTypes.LayoutControlItem && child.lcid?.mid) {
440
+ mids.push(child.lcid.mid);
441
+ }
442
+ else if (child.type === LayoutItemTypes.LayoutGroup) {
443
+ mids.push(...findMidsInGroup(child.layoutItemID));
444
+ }
445
+ }
446
+ return mids;
447
+ };
448
+ // Per ogni tab, conta gli errori e raccoglie i dettagli
449
+ for (const tabGroup of tabGroups) {
450
+ const tabId = tabGroup.layoutItemID;
451
+ if (tabId === undefined)
452
+ continue;
453
+ const midsInTab = findMidsInGroup(tabId);
454
+ const errorDetails = [];
455
+ for (const mid of midsInTab) {
456
+ const md = metadataValues.find(m => m.mid === mid);
457
+ if (md) {
458
+ const validationItem = validationItems.find(v => v.PropertyName === md.md?.nameLoc);
459
+ if (validationItem) {
460
+ errorDetails.push({
461
+ fieldName: md.md?.nameLoc ?? '',
462
+ message: validationItem.Message ?? ''
463
+ });
464
+ }
465
+ }
466
+ }
467
+ if (errorDetails.length > 0) {
468
+ map.set(tabId, { count: errorDetails.length, details: errorDetails });
469
+ }
470
+ }
471
+ return map;
472
+ }, [layout, metadataValues, validationItems]);
425
473
  const layoutDsAttachs = useMemo(() => {
426
474
  const dsAttachsData = [];
427
475
  metadataValues.forEach(item => {
@@ -465,22 +513,56 @@ const TMMetadataValues = ({ showCheckBoxes = ShowCheckBoxesMode.Never, checkPerm
465
513
  }
466
514
  return layout.items?.filter(item => item.parentID === parentID) || [];
467
515
  };
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).
516
+ /**
517
+ * Renderizza ricorsivamente l'albero del layout partendo dalla radice e scendendo verso i figli.
518
+ *
519
+ * Tipi gestiti:
520
+ * - LayoutRoot: elemento radice, renderizza i figli come tab (se showTab) o come contenitore semplice
521
+ * - LayoutGroup: contenitori con orientamento (Vertical/Horizontal) e stili bordo (NoBorder, Group, GroupBox, Tabbed)
522
+ * - LayoutControlItem: campi metadata terminali, recuperati tramite MID e passati a renderMetadataItem
523
+ * - SeparatorItem: linee di separazione orizzontali
524
+ *
525
+ * @param layoutItem - elemento del layout da renderizzare
526
+ * @param depth - profondità di annidamento per calcolare l'indentazione (default 0)
527
+ * @param visited - Set di ID già visitati per prevenire cicli infiniti in layout malformati
528
+ */
471
529
  const renderLayoutItem = (layoutItem, depth = 0, visited = new Set()) => {
472
530
  const id = layoutItem.layoutItemID ?? 0;
473
531
  if (visited.has(id))
474
532
  return null;
475
533
  visited.add(id);
534
+ // Helper: renderizza i children di un layout item
535
+ const renderChildren = (parentItem, childDepth) => {
536
+ const itemChildren = getChildren(parentItem.layoutItemID);
537
+ return itemChildren.map(child => (_jsx(React.Fragment, { children: renderLayoutItem(child, childDepth, visited) }, `child-${child.layoutItemID}`)));
538
+ };
476
539
  // Check if this is a LayoutRoot - just render its children
477
540
  if (layoutItem.type === LayoutItemTypes.LayoutRoot) {
478
541
  const children = getChildren(layoutItem.layoutItemID);
479
542
  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}`));
543
+ // Per ogni figlio che è un LayoutGroup tab, costruisce i dati per il TabPanel
544
+ // Segna ogni LayoutGroup come visitato per prevenire cicli
545
+ const tabItems = [];
546
+ for (const child of children) {
547
+ const childId = child.layoutItemID ?? 0;
548
+ if (visited.has(childId))
549
+ continue;
550
+ visited.add(childId);
551
+ const childChildren = getChildren(child.layoutItemID);
552
+ const childContent = (_jsx("div", { style: { width: '100%' }, children: childChildren.map(grandChild => (_jsx(React.Fragment, { children: renderLayoutItem(grandChild, depth + 1, visited) }, `grandchild-${grandChild.layoutItemID}`))) }));
553
+ const errorData = tabErrorCountMap.get(childId);
554
+ tabItems.push({
555
+ layoutItemID: child.layoutItemID,
556
+ content: childContent,
557
+ title: (child.type === LayoutItemTypes.LayoutGroup && child.lgd?.caption) || `Tab ${child.layoutItemID}`,
558
+ errorCount: errorData?.count || 0,
559
+ errorDetails: errorData?.details || []
560
+ });
561
+ }
562
+ return (_jsx(React.Fragment, { children: _jsx(TMLayoutTabPanel, { tabItems: tabItems }) }, `root-${layoutItem.layoutItemID}`));
481
563
  }
482
564
  else {
483
- return (_jsx(React.Fragment, { children: children.map(child => (_jsx(React.Fragment, { children: renderLayoutItem(child, depth, visited) }, `child-${child.layoutItemID}`))) }, `root-${layoutItem.layoutItemID}`));
565
+ return (_jsx(React.Fragment, { children: renderChildren(layoutItem, depth) }, `root-${layoutItem.layoutItemID}`));
484
566
  }
485
567
  }
486
568
  // Check if this is a LayoutGroup
@@ -490,42 +572,55 @@ const TMMetadataValues = ({ showCheckBoxes = ShowCheckBoxesMode.Never, checkPerm
490
572
  const groupTitle = groupDescriptor.caption || `Group ${layoutItem.layoutItemID}`;
491
573
  const groupIsNoBorder = groupDescriptor.borderStyle == undefined || groupDescriptor.borderStyle == LayoutGroupBorderStyles.NoBorder || groupDescriptor.borderStyle == LayoutGroupBorderStyles.None;
492
574
  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}`));
575
+ const isVertical = groupDescriptor.orientation === LayoutGroupOrientations.Vertical;
576
+ const isHorizontal = groupDescriptor.orientation === LayoutGroupOrientations.Horizontal;
577
+ const nextDepth = depth + 1;
578
+ // Stile comune per gruppi con bordo e titolo
579
+ const borderedGroupStyle = (flexDir) => ({
580
+ position: 'relative',
581
+ border: '2px solid #CAD9EB',
582
+ borderRadius: '3px',
583
+ padding: '12px 6px 6px',
584
+ margin: '10px',
585
+ display: 'flex',
586
+ flexDirection: flexDir,
587
+ flexWrap: 'wrap',
588
+ gap: '3px'
589
+ });
590
+ 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 }));
591
+ // Layout Group da trasformare in tab - il rendering è già gestito da LayoutRoot
592
+ if (isVertical && layout.showTab && layoutItem.parentID === 0) {
593
+ return null;
496
594
  }
497
- if (groupIsNoBorder && groupDescriptor.orientation !== LayoutGroupOrientations.Horizontal && children.length == 0) {
498
- return (_jsx("br", {}));
595
+ // Gruppo vuoto senza bordo (non orizzontale) line break
596
+ if (groupIsNoBorder && !isHorizontal && children.length === 0) {
597
+ return _jsx("br", {});
499
598
  }
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
- );
599
+ // Orizzontale con bordo, children e titolo
600
+ if (!groupIsNoBorder && isHorizontal && children.length > 0 && groupTitle.length > 0) {
601
+ return (_jsxs("div", { style: borderedGroupStyle('row'), children: [groupTitleElement, renderChildren(layoutItem, nextDepth)] }, `group-horizontal-${layoutItem.layoutItemID}`));
506
602
  }
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}`))) }));
603
+ // Verticale senza bordo
604
+ if (groupIsNoBorder && isVertical) {
605
+ return (_jsx("div", { style: { width: '100%', border: 'none', padding: 0 }, children: renderChildren(layoutItem, nextDepth) }));
509
606
  }
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}`)))] }));
607
+ // Verticale con bordo
608
+ if (!groupIsNoBorder && isVertical) {
609
+ if (groupDescriptor.borderStyle === LayoutGroupBorderStyles.Group) {
610
+ return (_jsxs("div", { style: borderedGroupStyle('column'), children: [groupTitleElement, renderChildren(layoutItem, nextDepth)] }));
513
611
  }
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}`))) }));
612
+ if (groupDescriptor.borderStyle === LayoutGroupBorderStyles.GroupBox || groupDescriptor.borderStyle === LayoutGroupBorderStyles.Tabbed) {
613
+ return (_jsx(TMAccordion, { title: groupTitle, titleSize: "Small", children: renderChildren(layoutItem, nextDepth) }));
516
614
  }
517
615
  }
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}`));
616
+ // Orizzontale
617
+ if (isHorizontal) {
618
+ const renderHorizontalChildren = () => children.map(child => (_jsx("div", { style: { flex: '1 1 0', minWidth: 0 }, children: renderLayoutItem(child, nextDepth, visited) }, child.layoutItemID)));
619
+ 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
620
  }
526
- // Apply indentation only to subgroups (depth > 0), not to root groups
621
+ // Fallback: gruppo con accordion e indentazione
527
622
  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}`));
623
+ 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
624
  }
530
625
  // Check if this is a LayoutControlItem (metadata field)
531
626
  else if (layoutItem.type === LayoutItemTypes.LayoutControlItem && layoutItem.lcid) {
@@ -559,7 +654,7 @@ const TMMetadataValues = ({ showCheckBoxes = ShowCheckBoxesMode.Never, checkPerm
559
654
  const visited = new Set();
560
655
  return rootItems.map(item => (_jsx(React.Fragment, { children: renderLayoutItem(item, 0, visited) }, `root-item-${item.layoutItemID}`)));
561
656
  })() }));
562
- }, [layout, metadataValues, showCheckBoxes, showNullValueCheckBoxes, isReadOnly, dynDataListsToBeRefreshed, validationItems, selectedMID, isOpenDistinctValues, openChooserBySingleClick, metadataValuesOrig]);
657
+ }, [layout, metadataValues, showCheckBoxes, showNullValueCheckBoxes, isReadOnly, dynDataListsToBeRefreshed, validationItems, selectedMID, isOpenDistinctValues, openChooserBySingleClick, metadataValuesOrig, tabErrorCountMap]);
563
658
  const renderForm = useMemo(() => {
564
659
  // Se currentDTD non è ancora stato caricato, non renderizzare nulla
565
660
  if (!currentDTD) {
@@ -611,3 +706,58 @@ const StyledSeparator = styled.hr `
611
706
  border: none;
612
707
  border-top: 1px solid #e0e0e0;
613
708
  `;
709
+ const StyledErrorBadge = styled.span `
710
+ display: inline-flex;
711
+ align-items: center;
712
+ justify-content: center;
713
+ min-width: 18px;
714
+ height: 18px;
715
+ padding: 0 5px;
716
+ border-radius: 9px;
717
+ background-color: #c62828;
718
+ color: white;
719
+ font-size: 0.75rem;
720
+ font-weight: bold;
721
+ line-height: 1;
722
+ margin-left: 6px;
723
+ `;
724
+ const TMLayoutTabPanel = React.memo(({ tabItems }) => {
725
+ const [activeTabIndex, setActiveTabIndex] = useState(0);
726
+ const handleSelectedIndexChange = useCallback((index) => {
727
+ setActiveTabIndex(index);
728
+ }, []);
729
+ 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: {
730
+ minWidth: '240px',
731
+ padding: '14px',
732
+ borderRadius: '10px',
733
+ background: '#ffffff',
734
+ boxShadow: '0 6px 16px rgba(0,0,0,0.08)',
735
+ border: '1px solid #e5e7eb',
736
+ color: '#1f2937',
737
+ fontFamily: 'sans-serif'
738
+ }, children: [_jsx("div", { style: {
739
+ fontWeight: 600,
740
+ textAlign: 'center',
741
+ fontSize: '1.05em',
742
+ marginBottom: '10px',
743
+ color: '#b91c1c'
744
+ }, children: tabItem.errorCount === 1 ? "1 campo non valido" : `${tabItem.errorCount} campi non validi` }), _jsx("div", { style: {
745
+ height: '1px',
746
+ background: '#e5e7eb',
747
+ marginBottom: '10px'
748
+ } }), _jsx("div", { style: { display: 'flex', flexDirection: 'column', gap: '10px' }, children: tabItem.errorDetails?.map((error, idx) => (_jsxs("div", { style: {
749
+ padding: '10px',
750
+ borderRadius: '8px',
751
+ background: '#fef2f2',
752
+ border: '1px solid #fecaca'
753
+ }, children: [_jsx("div", { style: {
754
+ fontWeight: 600,
755
+ fontSize: '0.95em',
756
+ marginBottom: '3px',
757
+ color: '#991b1b'
758
+ }, children: error.fieldName }), _jsx("div", { style: {
759
+ fontSize: '0.85em',
760
+ color: '#7f1d1d',
761
+ lineHeight: 1.4
762
+ }, 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}`))) }));
763
+ });
@@ -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;
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
3
3
  import TMDcmtPreview from './TMDcmtPreview';
4
- import { AccessLevels, AppModules, ArchiveConstraints, ArchiveEngineByID, DcmtTypeListCacheService, LayoutCacheService, LayoutModes, MetadataDataTypes, ObjectClasses, ResultTypes, SDK_Globals, SDK_Localizator, SystemMIDsAsNumber, SystemTIDs, Task_States, TID_DID, UpdateEngineByID, UserListCacheService, ValidationItem, WorkflowCacheService, WorkItemMetadataNames } from '@topconsultnpm/sdk-ts';
4
+ import { AccessLevels, AppModules, ArchiveConstraints, ArchiveEngineByID, DcmtTypeListCacheService, LayoutCacheService, LayoutModes, MetadataDataDomains, MetadataDataTypes, ObjectClasses, ResultTypes, SDK_Globals, SDK_Localizator, SystemMIDsAsNumber, SystemTIDs, Task_States, TID_DID, UpdateEngineByID, UserListCacheService, ValidationItem, WorkflowCacheService, WorkItemMetadataNames } from '@topconsultnpm/sdk-ts';
5
5
  import { WorkFlowApproveRejectPopUp, WorkFlowMoreInfoPopUp, WorkFlowOperationButtons, WorkFlowReAssignPopUp } from '../workflow/TMWorkflowPopup';
6
6
  import { DownloadTypes, FormModes, DcmtOperationTypes } from '../../../ts';
7
7
  import { DeviceType, useDeviceType } from '../../base/TMDeviceProvider';
@@ -1745,7 +1745,12 @@ export const validateMetadataList = (mvdList = []) => {
1745
1745
  return validationItems;
1746
1746
  }, []);
1747
1747
  };
1748
- const isValidForValidation = (mvd) => { return mvd.mid > 99; };
1748
+ const isValidForValidation = (mvd) => {
1749
+ // I campi Computed non vanno validati (sono calcolati automaticamente)
1750
+ if (mvd.md?.dataDomain === MetadataDataDomains.Computed)
1751
+ return false;
1752
+ return mvd.mid > 99;
1753
+ };
1749
1754
  const validateRequiredField = (mvd, value, validationItems) => {
1750
1755
  if (mvd.isRequired === '1' && !value.trim()) {
1751
1756
  const message = SDKUI_Localizator.RequiredField;
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useEffect, useState } from "react";
3
3
  import { SDK_Globals } from "@topconsultnpm/sdk-ts";
4
- import { IconCopy, getExceptionMessage } from "../../../helper";
4
+ import { IconCopy, getExceptionMessage, SDKUI_Localizator } from "../../../helper";
5
5
  import TMSpinner from "../../base/TMSpinner";
6
6
  const TMSignatureInfoContent = (props) => {
7
7
  const { inputDcmt } = props;
@@ -105,12 +105,16 @@ const TMSignatureInfoContent = (props) => {
105
105
  gap: '10px',
106
106
  fontSize: '13px'
107
107
  }, children: [_jsxs("div", { children: [_jsx("strong", { style: { color: '#555' }, children: "Intestatario:" }), _jsx("div", { style: { marginTop: '4px', color: '#333' }, children: signer.info1 ?? '-' })] }), _jsxs("div", { children: [_jsx("strong", { style: { color: '#555' }, children: "Riferimento temporale:" }), _jsx("div", { style: { marginTop: '4px', color: '#333' }, children: signer.info2 ?? '-' })] }), _jsxs("div", { children: [_jsx("strong", { style: { color: '#555' }, children: "Dettagli:" }), _jsx("div", { style: { marginTop: '4px', color: '#333' }, children: signer.info3 ?? '-' })] })] })] }, idx)))] })) : (_jsx("div", { style: {
108
- padding: '20px',
108
+ border: "1px solid #d0d0d0",
109
+ borderRadius: "8px",
110
+ padding: "16px",
111
+ marginBottom: "12px",
112
+ background: "linear-gradient(135deg, #ffffff 0%, #f9f9f9 100%)",
113
+ boxShadow: "0 2px 4px rgba(0,0,0,0.08)",
114
+ userSelect: 'text',
109
115
  textAlign: 'center',
110
- color: '#666',
111
- background: '#f5f5f5',
112
- borderRadius: '8px'
113
- }, children: "Nessuna firma trovata" })), signerInfo.shA256 && (_jsxs("div", { style: {
116
+ color: '#666'
117
+ }, children: SDKUI_Localizator.NoSignatureFound })), signerInfo.shA256 && (_jsxs("div", { style: {
114
118
  marginBottom: '12px',
115
119
  padding: '16px',
116
120
  background: '#f5f5f5',
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useEffect, useMemo, useState } from "react";
3
- import { SDK_Globals, UserListCacheService, WFEvents, WorkflowCacheService } from '@topconsultnpm/sdk-ts';
3
+ import { ResultTypes, SDK_Globals, UserListCacheService, ValidationItem, WFEvents, WorkflowCacheService } from '@topconsultnpm/sdk-ts';
4
4
  import styled from "styled-components";
5
5
  import { SDKUI_Localizator, IconApply, IconCloseOutline, IconUser, IconInfo, IconSignaturePencil, isSign4TopEnabled, IconCheck, IconCloseCircle, IconStop, taskModalSizes } from "../../../helper";
6
6
  import { TMColors } from "../../../utils/theme";
@@ -10,6 +10,7 @@ import TMModal from "../../base/TMModal";
10
10
  import { TMExceptionBoxManager } from "../../base/TMPopUp";
11
11
  import TMSpinner from "../../base/TMSpinner";
12
12
  import TMUserChooser from "../../choosers/TMUserChooser";
13
+ import TMTextArea from "../../editors/TMTextArea";
13
14
  import ShowAlert from "../../base/TMAlert";
14
15
  import { FormModes } from "../../../ts";
15
16
  import TMTaskForm from "../tasks/TMTaskForm";
@@ -19,17 +20,6 @@ const StyledWorkFlowOperationButtonsContainer = styled.div `
19
20
  gap: 10px;
20
21
  flex-direction: column;
21
22
  `;
22
- const StyledTextArea = styled.textarea `
23
- width: 100%;
24
- height: 100%;
25
- border: 1px solid ${(props) => (props.$isValid ? '#b4b4b4' : TMColors.error)};
26
- border-radius: 10px;
27
- padding: 10px;
28
- &:focus {
29
- outline: none;
30
- border-bottom: 4px solid ${(props) => (props.$isValid ? TMColors.primaryColor : TMColors.error)};
31
- }
32
- `;
33
23
  const CharacterCounter = styled.div `
34
24
  text-align: right;
35
25
  font-size: 0.8rem;
@@ -102,7 +92,7 @@ export const WorkFlowApproveRejectPopUp = ({ TID = 0, DID = 0, deviceType = Devi
102
92
  const workflowAction = isReject === 0 ? SDKUI_Localizator.Approve : SDKUI_Localizator.Reject;
103
93
  const itemCount = selectedItems.length > 0 ? `(${selectedItems.length} workitem)` : '';
104
94
  const title = `${workflowAction} ${itemCount}`;
105
- return (_jsx(TMModal, { title: title, onClose: onClose, width: '600px', height: '270px', isModal: true, children: _jsxs(StyledModalBodyWrapper, { children: [_jsxs(StyledModalContentContainer, { children: [_jsxs("p", { style: { color: (isReject === 1 && disable) ? TMColors.error : 'black' }, children: [SDKUI_Localizator.CommentText, " ", isReject === 1 && disable && _jsx("span", { children: ` (${SDKUI_Localizator.RequiredField})` }), " "] }), _jsx(StyledTextArea, { maxLength: 200, "$isValid": isReject === 0 ? true : !disable, value: commentValue, onChange: (e) => setCommentValue(e.target.value) }), _jsx(CharacterCounter, { children: `${200 - commentValue.length} ${SDKUI_Localizator.CharactersRemaining}` })] }), _jsx(StyledModalFooter, { children: isReject === 0
95
+ return (_jsx(TMModal, { title: title, onClose: onClose, width: '600px', height: '270px', isModal: true, children: _jsxs(StyledModalBodyWrapper, { children: [_jsxs(StyledModalContentContainer, { children: [_jsx(TMTextArea, { label: SDKUI_Localizator.CommentText, value: commentValue, onValueChanged: (e) => setCommentValue(e.target.value), validationItems: isReject === 1 && disable ? [new ValidationItem(ResultTypes.ERROR, 'comment', SDKUI_Localizator.RequiredField)] : [], maxLength: 200, fillHeight: true }), commentValue.length > 0 && _jsx(CharacterCounter, { children: `${200 - commentValue.length} ${SDKUI_Localizator.CharactersRemaining}` })] }), _jsx(StyledModalFooter, { children: isReject === 0
106
96
  ? _jsx(TMButton, { btnStyle: 'advanced', showTooltip: false, icon: _jsx(IconApply, {}), caption: SDKUI_Localizator.Approve, disabled: false, onClick: () => completeOrRejectAsync(isReject), advancedColor: TMColors.success })
107
97
  : _jsx(TMButton, { btnStyle: 'advanced', showTooltip: false, icon: _jsx(IconCloseOutline, {}), caption: SDKUI_Localizator.Reject, disabled: disable, onClick: () => { !disable && completeOrRejectAsync(isReject); }, advancedColor: TMColors.error }) })] }) }));
108
98
  };
@@ -110,7 +100,7 @@ export const WorkFlowReAssignPopUp = ({ DID = 0, TID = 0, deviceType = DeviceTyp
110
100
  const [commentValue, setCommentValue] = useState('');
111
101
  const [selectedUserID, setSelectedUserID] = useState([]);
112
102
  const [participants, setParticipants] = useState([]);
113
- const disable = commentValue.length === 0 || !selectedUserID;
103
+ const disable = commentValue.length === 0 || selectedUserID.length === 0;
114
104
  // Determina se siamo nel contesto CtrlWorkflow (quando abbiamo workItemDetail)
115
105
  const isCtrlWorkflowContext = !!workItemDetail;
116
106
  const reAssignWorkFlowAsync = async () => {
@@ -175,9 +165,9 @@ export const WorkFlowReAssignPopUp = ({ DID = 0, TID = 0, deviceType = DeviceTyp
175
165
  // Determina il conteggio degli item da mostrare nel titolo
176
166
  const itemCount = workItemDetail ? 1 : selectedItems.length;
177
167
  const titleSuffix = itemCount > 0 ? ` (${itemCount} workitem)` : '';
178
- return (_jsx(TMModal, { onClose: onClose, width: '600px', height: '270px', isModal: true, title: SDKUI_Localizator.Reassign + titleSuffix, children: _jsxs(StyledModalBodyWrapper, { children: [_jsxs(StyledModalContentContainer, { children: [_jsx(TMUserChooser, { dataSource: participants, values: selectedUserID, onValueChanged: (IDs) => {
168
+ return (_jsx(TMModal, { onClose: onClose, width: '600px', height: '350px', isModal: true, title: SDKUI_Localizator.Reassign + titleSuffix, children: _jsxs(StyledModalBodyWrapper, { children: [_jsxs(StyledModalContentContainer, { children: [_jsx(TMUserChooser, { label: SDKUI_Localizator.AssignTo, dataSource: participants, validationItems: selectedUserID.length === 0 ? [new ValidationItem(ResultTypes.ERROR, 'selectedUser', SDKUI_Localizator.RequiredField)] : [], values: selectedUserID, onValueChanged: (IDs) => {
179
169
  setSelectedUserID(IDs ?? []);
180
- } }), _jsxs("p", { style: { color: commentValue.length === 0 ? TMColors.error : 'black' }, children: [SDKUI_Localizator.CommentText, " ", commentValue.length === 0 && _jsx("span", { children: ` (${SDKUI_Localizator.RequiredField})` }), " "] }), _jsx(StyledTextArea, { maxLength: 200, "$isValid": commentValue.length !== 0, value: commentValue, onChange: (e) => setCommentValue(e.target.value) }), _jsx(CharacterCounter, { children: `${200 - commentValue.length} ${SDKUI_Localizator.CharactersRemaining}` })] }), _jsx(StyledModalFooter, { children: _jsx(TMButton, { btnStyle: 'advanced', showTooltip: false, icon: _jsx(IconUser, { fontSize: 16 }), caption: SDKUI_Localizator.Reassign, disabled: disable, onClick: () => !disable && reAssignWorkFlowAsync(), advancedColor: TMColors.tertiary }) })] }) }));
170
+ } }), _jsx(TMTextArea, { label: SDKUI_Localizator.CommentText, value: commentValue, onValueChanged: (e) => setCommentValue(e.target.value), validationItems: commentValue.length === 0 ? [new ValidationItem(ResultTypes.ERROR, 'comment', SDKUI_Localizator.RequiredField)] : [], maxLength: 200, fillHeight: true, elementStyle: { marginTop: '10px', flex: 1 } }), commentValue.length > 0 && _jsx(CharacterCounter, { children: `${200 - commentValue.length} ${SDKUI_Localizator.CharactersRemaining}` })] }), _jsx(StyledModalFooter, { children: _jsx(TMButton, { btnStyle: 'advanced', showTooltip: false, icon: _jsx(IconUser, { fontSize: 16 }), caption: SDKUI_Localizator.Reassign, disabled: disable, onClick: () => !disable && reAssignWorkFlowAsync(), advancedColor: TMColors.tertiary }) })] }) }));
181
171
  };
182
172
  /**
183
173
  * Modal per forzare l'approvazione di un work item
@@ -208,7 +198,7 @@ export const WorkflowForceApproveModal = ({ detail, onClose, onCompleted }) => {
208
198
  };
209
199
  const userName = detail.toUser?.name ?? detail.to;
210
200
  const title = `Forza completamento - ${userName}`;
211
- return (_jsx(TMModal, { title: title, onClose: onClose, width: '600px', height: '270px', isModal: true, children: _jsxs(StyledModalBodyWrapper, { children: [_jsxs(StyledModalContentContainer, { children: [_jsx("div", { style: { fontWeight: 600, marginBottom: '8px' }, children: "Motivazione (obbligatorio):" }), _jsx(StyledTextArea, { "$isValid": !disable, value: commentValue, onChange: (e) => setCommentValue(e.target.value), placeholder: "Inserisci il motivo della forzatura...", maxLength: 200 }), _jsxs(CharacterCounter, { children: [commentValue.length, "/200"] })] }), _jsx(StyledModalFooter, { children: _jsx(TMButton, { btnStyle: 'advanced', showTooltip: false, icon: _jsx(IconCheck, {}), caption: "Forza approvazione", width: '180px', disabled: disable, onClick: () => !disable && forceApproveAsync(), advancedColor: TMColors.success }) })] }) }));
201
+ return (_jsx(TMModal, { title: title, onClose: onClose, width: '600px', height: '270px', isModal: true, children: _jsxs(StyledModalBodyWrapper, { children: [_jsxs(StyledModalContentContainer, { children: [_jsx(TMTextArea, { label: "Motivazione", value: commentValue, onValueChanged: (e) => setCommentValue(e.target.value), validationItems: disable ? [new ValidationItem(ResultTypes.ERROR, 'comment', SDKUI_Localizator.RequiredField)] : [], placeHolder: "Inserisci il motivo della forzatura...", maxLength: 200, fillHeight: true }), commentValue.length > 0 && _jsxs(CharacterCounter, { children: [commentValue.length, "/200"] })] }), _jsx(StyledModalFooter, { children: _jsx(TMButton, { btnStyle: 'advanced', showTooltip: false, icon: _jsx(IconCheck, {}), caption: "Forza approvazione", width: '180px', disabled: disable, onClick: () => !disable && forceApproveAsync(), advancedColor: TMColors.success }) })] }) }));
212
202
  };
213
203
  /**
214
204
  * Modal per forzare il rifiuto di un work item
@@ -239,7 +229,7 @@ export const WorkflowForceRejectModal = ({ detail, onClose, onCompleted }) => {
239
229
  };
240
230
  const userName = detail.toUser?.name ?? detail.to;
241
231
  const title = `Forza rifiuto - ${userName}`;
242
- return (_jsx(TMModal, { title: title, onClose: onClose, width: '600px', height: '270px', isModal: true, children: _jsxs(StyledModalBodyWrapper, { children: [_jsxs(StyledModalContentContainer, { children: [_jsx("div", { style: { fontWeight: 600, marginBottom: '8px' }, children: "Motivazione (obbligatorio):" }), _jsx(StyledTextArea, { "$isValid": !disable, value: commentValue, onChange: (e) => setCommentValue(e.target.value), placeholder: "Inserisci il motivo del rifiuto...", maxLength: 200 }), _jsxs(CharacterCounter, { children: [commentValue.length, "/200"] })] }), _jsx(StyledModalFooter, { children: _jsx(TMButton, { btnStyle: 'advanced', showTooltip: false, icon: _jsx(IconCloseCircle, {}), caption: "Forza rifiuto", width: '150px', disabled: disable, onClick: () => !disable && forceRejectAsync(), advancedColor: TMColors.error }) })] }) }));
232
+ return (_jsx(TMModal, { title: title, onClose: onClose, width: '600px', height: '270px', isModal: true, children: _jsxs(StyledModalBodyWrapper, { children: [_jsxs(StyledModalContentContainer, { children: [_jsx(TMTextArea, { label: "Motivazione", value: commentValue, onValueChanged: (e) => setCommentValue(e.target.value), validationItems: disable ? [new ValidationItem(ResultTypes.ERROR, 'comment', SDKUI_Localizator.RequiredField)] : [], placeHolder: "Inserisci il motivo del rifiuto...", maxLength: 200, fillHeight: true }), commentValue.length > 0 && _jsxs(CharacterCounter, { children: [commentValue.length, "/200"] })] }), _jsx(StyledModalFooter, { children: _jsx(TMButton, { btnStyle: 'advanced', showTooltip: false, icon: _jsx(IconCloseCircle, {}), caption: "Forza rifiuto", width: '150px', disabled: disable, onClick: () => !disable && forceRejectAsync(), advancedColor: TMColors.error }) })] }) }));
243
233
  };
244
234
  /**
245
235
  * Modal per terminare le istanze workflow selezionate
@@ -278,7 +268,7 @@ export const WorkflowEndInstanceModal = ({ selectedInstances, onClose, onComplet
278
268
  const title = selectedInstances.length === 1
279
269
  ? `${SDKUI_Localizator.WorkflowEndInstance} (DID: ${selectedInstances[0].did})`
280
270
  : `${SDKUI_Localizator.WorkflowEndInstance} (${selectedInstances.length} istanze)`;
281
- return (_jsx(TMModal, { title: title, onClose: onClose, width: '600px', height: '270px', isModal: true, children: _jsxs(StyledModalBodyWrapper, { children: [_jsxs(StyledModalContentContainer, { children: [_jsx("div", { style: { fontWeight: 600, marginBottom: '8px' }, children: "Motivazione (obbligatorio):" }), _jsx(StyledTextArea, { "$isValid": !disable, value: commentValue, onChange: (e) => setCommentValue(e.target.value), placeholder: "Inserisci il motivo della terminazione...", maxLength: 200 }), _jsxs(CharacterCounter, { children: [commentValue.length, "/200"] })] }), _jsx(StyledModalFooter, { children: _jsx(TMButton, { btnStyle: 'advanced', showTooltip: false, icon: _jsx(IconStop, {}), caption: SDKUI_Localizator.WorkflowEndInstance, width: '150px', disabled: disable, onClick: () => !disable && endInstancesAsync(), advancedColor: TMColors.error }) })] }) }));
271
+ return (_jsx(TMModal, { title: title, onClose: onClose, width: '600px', height: '270px', isModal: true, children: _jsxs(StyledModalBodyWrapper, { children: [_jsxs(StyledModalContentContainer, { children: [_jsx(TMTextArea, { label: "Motivazione", value: commentValue, onValueChanged: (e) => setCommentValue(e.target.value), validationItems: disable ? [new ValidationItem(ResultTypes.ERROR, 'comment', SDKUI_Localizator.RequiredField)] : [], placeHolder: "Inserisci il motivo della terminazione...", maxLength: 200, fillHeight: true }), commentValue.length > 0 && _jsxs(CharacterCounter, { children: [commentValue.length, "/200"] })] }), _jsx(StyledModalFooter, { children: _jsx(TMButton, { btnStyle: 'advanced', showTooltip: false, icon: _jsx(IconStop, {}), caption: SDKUI_Localizator.WorkflowEndInstance, width: '150px', disabled: disable, onClick: () => !disable && endInstancesAsync(), advancedColor: TMColors.error }) })] }) }));
282
272
  };
283
273
  export const WorkFlowMoreInfoPopUp = (props) => {
284
274
  const { fromDTD, DID = 0, TID = 0, deviceType = DeviceType.DESKTOP, onClose, onCompleted, allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTaskCallback, editTaskCallback, handleNavigateToWGs, handleNavigateToDossiers, triggerBlogRefresh } = props;
@@ -1343,9 +1343,24 @@ const WFDiagram = ({ xmlDiagramString, currentSetID, allowEdit = true, onDiagram
1343
1343
  const newStatus = connection.OutputStatus === WorkItemStatus.Completed
1344
1344
  ? WorkItemStatus.Rejected
1345
1345
  : WorkItemStatus.Completed;
1346
+ const oppositeStatus = newStatus === WorkItemStatus.Completed
1347
+ ? WorkItemStatus.Rejected
1348
+ : WorkItemStatus.Completed;
1349
+ // Se esiste un'altra connection dallo stesso source con il newStatus,
1350
+ // la si inverte in modo che non esistano mai 2 uscite con lo stesso OutputStatus.
1351
+ const sourceId = connection.Source.ParentDiagramItem.ID;
1352
+ const conflictingConn = wfDiagram.Connections.find(conn => conn.ID !== connectionId &&
1353
+ conn.Source.ParentDiagramItem.ID === sourceId &&
1354
+ conn.OutputStatus === newStatus);
1346
1355
  const updatedDiagram = {
1347
1356
  ...wfDiagram,
1348
- Connections: wfDiagram.Connections.map(conn => conn.ID === connectionId ? { ...conn, OutputStatus: newStatus } : conn)
1357
+ Connections: wfDiagram.Connections.map(conn => {
1358
+ if (conn.ID === connectionId)
1359
+ return { ...conn, OutputStatus: newStatus };
1360
+ if (conflictingConn && conn.ID === conflictingConn.ID)
1361
+ return { ...conn, OutputStatus: oppositeStatus };
1362
+ return conn;
1363
+ })
1349
1364
  };
1350
1365
  updateDiagram(updatedDiagram);
1351
1366
  setWfDiagram(updatedDiagram);
@@ -1,6 +1,6 @@
1
- import { PlatformObjectValidator, QueryValidatorOptions, ResultTypes, TMPropertyNames, ValidationItem, WorkItemStatus } from '@topconsultnpm/sdk-ts';
1
+ import { PlatformObjectValidator, QueryValidatorOptions, ResultTypes, ValidationItem, WorkItemStatus } from '@topconsultnpm/sdk-ts';
2
2
  import { DiagramItemTypes, ArrowSymbol } from './interfaces'; // Assicurati che il percorso sia corretto
3
- import { generateUUID, SDKUI_Localizator } from '../../../../helper';
3
+ import { generateUUID, LocalizeDiagramItemType, SDKUI_Localizator } from '../../../../helper';
4
4
  /**
5
5
  * Calculates the angle in degrees of an arrow based on two points.
6
6
  * @param prevPoint The previous point on the trajectory.
@@ -318,72 +318,73 @@ export const workflowValidator = async (wf) => {
318
318
  const vil = await wfDiagramItemValidator(item);
319
319
  vil.forEach(v => v.PropertyScopes = ['diagramItem']);
320
320
  validationItems.push(...vil);
321
+ const itemType = LocalizeDiagramItemType(item.Type);
321
322
  switch (item.Type) {
322
323
  case DiagramItemTypes.Start:
323
324
  if (wf.Connections.filter(c => c.Source.ParentDiagramItem.ID === item.ID).length === 0) {
324
- validationItems.push(new ValidationItem(ResultTypes.ERROR, `item-${item.ID}`, SDKUI_Localizator.WorkflowDiagramStartMustHaveOutgoing, ['diagramItem']));
325
+ validationItems.push(new ValidationItem(ResultTypes.ERROR, itemType, SDKUI_Localizator.WorkflowDiagramStartMustHaveOutgoing, ['diagramItem']));
325
326
  }
326
327
  if (wf.Connections.filter(c => c.Sink.ParentDiagramItem.ID === item.ID).length > 0) {
327
- validationItems.push(new ValidationItem(ResultTypes.ERROR, `item-${item.ID}`, SDKUI_Localizator.WorkflowDiagramStartCannotHaveIncoming, ['diagramItem']));
328
+ validationItems.push(new ValidationItem(ResultTypes.ERROR, itemType, SDKUI_Localizator.WorkflowDiagramStartCannotHaveIncoming, ['diagramItem']));
328
329
  }
329
330
  break;
330
331
  case DiagramItemTypes.End:
331
332
  case DiagramItemTypes.Exit:
332
333
  if (wf.Connections.filter(c => c.Sink.ParentDiagramItem.ID === item.ID).length === 0) {
333
- validationItems.push(new ValidationItem(ResultTypes.ERROR, `item-${item.ID}`, `L'elemento '${DiagramItemTypes[item.Type]}' deve avere almeno una connessione in ingresso.`, ['diagramItem']));
334
+ validationItems.push(new ValidationItem(ResultTypes.ERROR, itemType, SDKUI_Localizator.WorkflowDiagramElementMustHaveIncoming.replaceParams(itemType), ['diagramItem']));
334
335
  }
335
336
  if (wf.Connections.filter(c => c.Source.ParentDiagramItem.ID === item.ID).length > 0) {
336
- validationItems.push(new ValidationItem(ResultTypes.ERROR, `item-${item.ID}`, `L'elemento '${DiagramItemTypes[item.Type]}' non può avere connessioni in uscita.`, ['diagramItem']));
337
+ validationItems.push(new ValidationItem(ResultTypes.ERROR, itemType, SDKUI_Localizator.WorkflowDiagramElementCannotHaveOutgoing.replaceParams(itemType), ['diagramItem']));
337
338
  }
338
339
  break;
339
340
  case DiagramItemTypes.Condition:
340
341
  if (wf.Connections.filter(c => c.Source.ParentDiagramItem.ID === item.ID).length !== 2) {
341
- validationItems.push(new ValidationItem(ResultTypes.WARNING, `item-${item.ID}`, SDKUI_Localizator.WorkflowDiagramConditionTwoOutgoing, ['diagramItem']));
342
+ validationItems.push(new ValidationItem(ResultTypes.WARNING, itemType, SDKUI_Localizator.WorkflowDiagramConditionTwoOutgoing.replaceParams(item.ItemName), ['diagramItem']));
342
343
  }
343
344
  if (wf.Connections.filter(c => c.Sink.ParentDiagramItem.ID === item.ID).length === 0) {
344
- validationItems.push(new ValidationItem(ResultTypes.ERROR, `item-${item.ID}`, SDKUI_Localizator.WorkflowDiagramConditionMustHaveIncoming, ['diagramItem']));
345
+ validationItems.push(new ValidationItem(ResultTypes.ERROR, itemType, SDKUI_Localizator.WorkflowDiagramConditionMustHaveIncoming.replaceParams(item.ItemName), ['diagramItem']));
345
346
  }
346
347
  break;
347
348
  case DiagramItemTypes.Approval:
348
349
  case DiagramItemTypes.ExecTask:
349
350
  case DiagramItemTypes.DataEntry:
350
351
  if (wf.Connections.filter(c => c.Source.ParentDiagramItem.ID === item.ID).length !== 2) {
351
- validationItems.push(new ValidationItem(ResultTypes.WARNING, `item-${item.ID}`, SDKUI_Localizator.WorkflowDiagramElementShouldHaveTwoOutgoing.replace('{0}', item.ItemName), ['diagramItem']));
352
+ validationItems.push(new ValidationItem(ResultTypes.WARNING, itemType, SDKUI_Localizator.WorkflowDiagramElementShouldHaveTwoOutgoing.replaceParams(item.ItemName), ['diagramItem']));
352
353
  }
353
354
  if (wf.Connections.filter(c => c.Sink.ParentDiagramItem.ID === item.ID).length === 0) {
354
- validationItems.push(new ValidationItem(ResultTypes.WARNING, `item-${item.ID}`, SDKUI_Localizator.WorkflowDiagramElementShouldHaveIncoming.replace('{0}', item.ItemName), ['diagramItem']));
355
+ validationItems.push(new ValidationItem(ResultTypes.WARNING, itemType, SDKUI_Localizator.WorkflowDiagramElementShouldHaveIncoming.replaceParams(item.ItemName), ['diagramItem']));
355
356
  }
356
357
  break;
357
358
  case DiagramItemTypes.Notification:
358
359
  if (wf.Connections.filter(c => c.Source.ParentDiagramItem.ID === item.ID).length === 0) {
359
- validationItems.push(new ValidationItem(ResultTypes.WARNING, `item-${item.ID}`, `L'elemento '${item.ItemName}' dovrebbe avere almeno una connessione in uscita.`, ['diagramItem']));
360
+ validationItems.push(new ValidationItem(ResultTypes.WARNING, itemType, SDKUI_Localizator.WorkflowDiagramElementShouldHaveOutgoing.replaceParams(item.ItemName), ['diagramItem']));
360
361
  }
361
362
  if (wf.Connections.filter(c => c.Sink.ParentDiagramItem.ID === item.ID).length === 0) {
362
- validationItems.push(new ValidationItem(ResultTypes.WARNING, `item-${item.ID}`, `L'elemento '${item.ItemName}' deve avere almeno una connessione in ingresso.`, ['diagramItem']));
363
+ validationItems.push(new ValidationItem(ResultTypes.WARNING, itemType, SDKUI_Localizator.WorkflowDiagramElementShouldHaveIncoming.replaceParams(item.ItemName), ['diagramItem']));
363
364
  }
364
365
  break;
365
366
  case DiagramItemTypes.UpdateDcmt:
366
367
  if (wf.Connections.filter(c => c.Source.ParentDiagramItem.ID === item.ID).length !== 1) {
367
- validationItems.push(new ValidationItem(ResultTypes.WARNING, `item-${item.ID}`, `L'elemento '${item.ItemName}' dovrebbe avere esattamente una connessione in uscita.`, ['diagramItem']));
368
+ validationItems.push(new ValidationItem(ResultTypes.WARNING, itemType, SDKUI_Localizator.WorkflowDiagramElementShouldHaveOneOutgoing.replaceParams(item.ItemName), ['diagramItem']));
368
369
  }
369
370
  if (wf.Connections.filter(c => c.Sink.ParentDiagramItem.ID === item.ID).length === 0) {
370
- validationItems.push(new ValidationItem(ResultTypes.WARNING, `item-${item.ID}`, `L'elemento '${item.ItemName}' deve avere almeno una connessione in ingresso.`, ['diagramItem']));
371
+ validationItems.push(new ValidationItem(ResultTypes.WARNING, itemType, SDKUI_Localizator.WorkflowDiagramElementShouldHaveIncoming.replaceParams(item.ItemName), ['diagramItem']));
371
372
  }
372
373
  break;
373
374
  case DiagramItemTypes.Status:
374
375
  if (wf.Connections.filter(c => c.Source.ParentDiagramItem.ID === item.ID).length !== 1) {
375
- validationItems.push(new ValidationItem(ResultTypes.WARNING, `item-${item.ID}`, `L'elemento '${item.ItemName}' dovrebbe avere esattamente una connessione in uscita.`, ['diagramItem']));
376
+ validationItems.push(new ValidationItem(ResultTypes.WARNING, itemType, SDKUI_Localizator.WorkflowDiagramElementShouldHaveOneOutgoing.replaceParams(item.ItemName), ['diagramItem']));
376
377
  }
377
378
  if (wf.Connections.filter(c => c.Sink.ParentDiagramItem.ID === item.ID).length === 0) {
378
- validationItems.push(new ValidationItem(ResultTypes.WARNING, `item-${item.ID}`, `L'elemento '${item.ItemName}' deve avere almeno una connessione in ingresso.`, ['diagramItem']));
379
+ validationItems.push(new ValidationItem(ResultTypes.WARNING, itemType, SDKUI_Localizator.WorkflowDiagramElementShouldHaveIncoming.replaceParams(item.ItemName), ['diagramItem']));
379
380
  }
380
381
  break;
381
382
  case DiagramItemTypes.RunApp:
382
383
  if (wf.Connections.filter(c => c.Source.ParentDiagramItem.ID === item.ID).length === 0) {
383
- validationItems.push(new ValidationItem(ResultTypes.WARNING, `item-${item.ID}`, `L'elemento '${item.ItemName}' dovrebbe avere almeno una connessione in uscita.`, ['diagramItem']));
384
+ validationItems.push(new ValidationItem(ResultTypes.WARNING, itemType, SDKUI_Localizator.WorkflowDiagramElementShouldHaveOutgoing.replaceParams(item.ItemName), ['diagramItem']));
384
385
  }
385
386
  if (wf.Connections.filter(c => c.Sink.ParentDiagramItem.ID === item.ID).length === 0) {
386
- validationItems.push(new ValidationItem(ResultTypes.WARNING, `item-${item.ID}`, `L'elemento '${item.ItemName}' deve avere almeno una connessione in ingresso.`, ['diagramItem']));
387
+ validationItems.push(new ValidationItem(ResultTypes.WARNING, itemType, SDKUI_Localizator.WorkflowDiagramElementShouldHaveIncoming.replaceParams(item.ItemName), ['diagramItem']));
387
388
  }
388
389
  break;
389
390
  }
@@ -480,7 +481,7 @@ export const wfDiagramItemValidator = async (d) => {
480
481
  qvo.DoOrderByValidation = false;
481
482
  await PlatformObjectValidator.QueryValidatorAsync(d.QD, vil, qvo);
482
483
  if (d.QD?.where === undefined || d.QD.where.length <= 0) {
483
- vil.push(new ValidationItem(ResultTypes.ERROR, TMPropertyNames.where, "La query della condizione non contiene criteri di selezione", [DiagramItemProps.QD]));
484
+ vil.push(new ValidationItem(ResultTypes.ERROR, LocalizeDiagramItemType(d.Type), `La query della condizione '${d.ItemName}' non contiene criteri di selezione`, [DiagramItemProps.QD]));
484
485
  }
485
486
  break;
486
487
  }
@@ -91,10 +91,14 @@ export declare class DevSettings {
91
91
  }
92
92
  export declare class AdvancedSettings {
93
93
  private _expertMode;
94
+ private _scannerLicense;
94
95
  get expertMode(): number;
95
96
  set expertMode(value: number);
97
+ get scannerLicense(): string;
98
+ set scannerLicense(value: string);
96
99
  toJSON(): {
97
100
  expertMode: number;
101
+ scannerLicense: string;
98
102
  };
99
103
  }
100
104
  export declare class CtrlWfSettings {
@@ -130,6 +130,7 @@ export class DevSettings {
130
130
  export class AdvancedSettings {
131
131
  constructor() {
132
132
  this._expertMode = 0;
133
+ this._scannerLicense = '';
133
134
  }
134
135
  get expertMode() {
135
136
  return this._expertMode;
@@ -142,10 +143,17 @@ export class AdvancedSettings {
142
143
  window.dispatchEvent(event);
143
144
  }
144
145
  }
146
+ get scannerLicense() {
147
+ return this._scannerLicense;
148
+ }
149
+ set scannerLicense(value) {
150
+ this._scannerLicense = value;
151
+ }
145
152
  // Override toJSON to control serialization (called by JSON.stringify)
146
153
  toJSON() {
147
154
  return {
148
- expertMode: this._expertMode, // Serialize only the public property
155
+ expertMode: this._expertMode,
156
+ scannerLicense: this._scannerLicense,
149
157
  };
150
158
  }
151
159
  }
@@ -54,6 +54,7 @@ export declare class SDKUI_Localizator {
54
54
  static get ArchiveDetailDocument(): "Detaildokument archivieren" | "Archive detail document" | "Archivar documento de detalle" | "Archiver le document détail" | "Arquivar documento de detalhe" | "Archivia documento dettaglio";
55
55
  static get ArchiveMasterDocument(): "Master-Dokument archivieren" | "Archive master document" | "Archivar documento maestro" | "Archiver le document maître" | "Arquivar documento mestre" | "Archivia documento master";
56
56
  static get Arguments(): "Themen" | "Arguments" | "Argumentos" | "Sujets" | "Tópicos" | "Argomenti";
57
+ static get AssignTo(): "Zuweisen an" | "Assign to" | "Asignar a" | "Assigner à" | "Atribuir a" | "Assegna a";
57
58
  static get AssignedBy(): "Zugewiesen von" | "Assigned by" | "Asignado por" | "Assigné par" | "Atribuído por" | "Assegnata da";
58
59
  static get AssignedByMe(): "Von mir zugewiesene" | "Assigned by me" | "Por mí" | "Que j'ai assignées" | "Atribuídas por mim" | "Assegnate da me";
59
60
  static get AssignedTo(): string;
@@ -430,6 +431,7 @@ export declare class SDKUI_Localizator {
430
431
  static get NoMessagesFound(): string;
431
432
  static get NoPanelSelected(): string;
432
433
  static get NoResultsFound(): string;
434
+ static get NoSignatureFound(): string;
433
435
  static get NoSource(): "Keine Quelle" | "No Source" | "Ninguna fuente" | "Aucune source" | "Nenhuma fonte" | "Nessun Origine";
434
436
  static get NoneSelection(): "Keine Auswahl" | "No selection" | "Ninguna selección" | "Pas de sélections" | "Nenhuma seleção" | "Nessuna selezione";
435
437
  static get NotAvailable(): string;
@@ -751,10 +753,14 @@ export declare class SDKUI_Localizator {
751
753
  static get WorkflowDiagramEndMissing(): "Il workflow deve contenere almeno un elemento di tipo 'End'." | "Workflow must contain at least one 'End' item." | "El workflow debe contener al menos un elemento de tipo 'End'." | "Le workflow doit contenir au moins un élément de type 'End'." | "O workflow deve conter pelo menos um elemento do tipo 'End'.";
752
754
  static get WorkflowDiagramStartMustHaveOutgoing(): "L'elemento 'Start' deve avere almeno una connessione in uscita." | "The 'Start' item must have at least one outgoing connection." | "El elemento 'Start' debe tener al menos una conexión de salida." | "L'élément 'Start' doit avoir au moins une connexion sortante." | "O elemento 'Start' deve ter pelo menos uma ligação de saída.";
753
755
  static get WorkflowDiagramStartCannotHaveIncoming(): "L'elemento 'Start' non può avere connessioni in ingresso." | "The 'Start' item cannot have incoming connections." | "El elemento 'Start' no puede tener conexiones de entrada." | "L'élément 'Start' ne peut pas avoir de connexions entrantes." | "O elemento 'Start' não pode ter ligações de entrada.";
754
- static get WorkflowDiagramConditionTwoOutgoing(): "L'elemento 'Condition' deve avere esattamente due connessioni in uscita." | "The 'Condition' item must have exactly two outgoing connections." | "El elemento 'Condition' debe tener exactamente dos conexiones de salida." | "L'élément 'Condition' doit avoir exactement deux connexions sortantes." | "O elemento 'Condition' deve ter exactamente duas ligações de saída.";
755
- static get WorkflowDiagramConditionMustHaveIncoming(): "L'elemento 'Condition' deve avere almeno una connessione in ingresso." | "The 'Condition' item must have at least one incoming connection." | "El elemento 'Condition' debe tener al menos una conexión de entrada." | "L'élément 'Condition' doit avoir au moins une connexion entrante." | "O elemento 'Condition' deve ter pelo menos uma ligação de entrada.";
756
- static get WorkflowDiagramElementShouldHaveTwoOutgoing(): "L'elemento '{0}' dovrebbe avere esattamente due connessioni in uscita." | "The element '{0}' should have exactly two outgoing connections." | "El elemento '{0}' debería tener exactamente dos conexiones de salida." | "L'élément '{0}' devrait avoir exactement deux connexions sortantes." | "O elemento '{0}' deveria ter exactamente duas ligações de saída.";
757
- static get WorkflowDiagramElementShouldHaveIncoming(): "L'elemento '{0}' deve avere almeno una connessione in ingresso." | "The element '{0}' must have at least one incoming connection." | "El elemento '{0}' debe tener al menos una conexión de entrada." | "L'élément '{0}' doit avoir au moins une connexion entrante." | "O elemento '{0}' deve ter pelo menos uma ligação de entrada.";
756
+ static get WorkflowDiagramConditionTwoOutgoing(): "L'elemento '{{0}}' deve avere esattamente due connessioni in uscita." | "The '{{0}}' item must have exactly two outgoing connections." | "El elemento '{{0}}' debe tener exactamente dos conexiones de salida." | "L'élément '{{0}}' doit avoir exactement deux connexions sortantes." | "O elemento '{{0}}' deve ter exactamente duas ligações de saída.";
757
+ static get WorkflowDiagramConditionMustHaveIncoming(): "L'elemento '{{0}}' deve avere almeno una connessione in ingresso." | "The '{{0}}' item must have at least one incoming connection." | "El elemento '{{0}}' debe tener al menos una conexión de entrada." | "L'élément '{{0}}' doit avoir au moins une connexion entrante." | "O elemento '{{0}}' deve ter pelo menos uma ligação de entrada.";
758
+ static get WorkflowDiagramElementShouldHaveTwoOutgoing(): "L'elemento '{{0}}' dovrebbe avere esattamente due connessioni in uscita." | "The element '{{0}}' should have exactly two outgoing connections." | "El elemento '{{0}}' debería tener exactamente dos conexiones de salida." | "L'élément '{{0}}' devrait avoir exactement deux connexions sortantes." | "O elemento '{{0}}' deveria ter exactamente duas ligações de saída.";
759
+ static get WorkflowDiagramElementShouldHaveIncoming(): "L'elemento '{{0}}' deve avere almeno una connessione in ingresso." | "El elemento '{{0}}' debe tener al menos una conexión de entrada." | "L'élément '{{0}}' doit avoir au moins une connexion entrante." | "O elemento '{{0}}' deve ter pelo menos uma ligação de entrada." | "The element '{{0}}' must have at least one incoming connection.";
760
+ static get WorkflowDiagramElementMustHaveIncoming(): "L'elemento '{{0}}' deve avere almeno una connessione in ingresso." | "El elemento '{{0}}' debe tener al menos una conexión de entrada." | "L'élément '{{0}}' doit avoir au moins une connexion entrante." | "O elemento '{{0}}' deve ter pelo menos uma ligação de entrada." | "The element '{{0}}' must have at least one incoming connection." | "Das Element '{{0}}' muss mindestens eine eingehende Verbindung haben.";
761
+ static get WorkflowDiagramElementCannotHaveOutgoing(): "Das Element '{{0}}' kann keine ausgehenden Verbindungen haben." | "The element '{{0}}' cannot have outgoing connections." | "El elemento '{{0}}' no puede tener conexiones de salida." | "L'élément '{{0}}' ne peut pas avoir de connexions sortantes." | "O elemento '{{0}}' não pode ter ligações de saída." | "L'elemento '{{0}}' non può avere connessioni in uscita.";
762
+ static get WorkflowDiagramElementShouldHaveOutgoing(): "Das Element '{{0}}' sollte mindestens eine ausgehende Verbindung haben." | "The element '{{0}}' should have at least one outgoing connection." | "El elemento '{{0}}' debería tener al menos una conexión de salida." | "L'élément '{{0}}' devrait avoir au moins une connexion sortante." | "O elemento '{{0}}' deveria ter pelo menos uma ligação de saída." | "L'elemento '{{0}}' dovrebbe avere almeno una connessione in uscita.";
763
+ static get WorkflowDiagramElementShouldHaveOneOutgoing(): "Das Element '{{0}}' sollte genau eine ausgehende Verbindung haben." | "The element '{{0}}' should have exactly one outgoing connection." | "El elemento '{{0}}' debería tener exactamente una conexión de salida." | "L'élément '{{0}}' devrait avoir exactement une connexion sortante." | "O elemento '{{0}}' deveria ter exactamente uma ligação de saída." | "L'elemento '{{0}}' dovrebbe avere esattamente una connessione in uscita.";
758
764
  static get WorkflowDiagramMissingOrInvalid(): "Diagramm fehlt oder ist ungültig" | "Diagram missing or invalid" | "Diagrama no presente o no válido" | "Schéma manquant ou invalide" | "Diagrama ausente ou inválido" | "Diagramma non presente o non valido";
759
765
  static get WorkflowDiagramNotAuthorized(): "Sie sind nicht berechtigt, das Diagramm anzuzeigen" | "You are not authorized to view the diagram" | "No está autorizado para ver el diagrama" | "Vous n'êtes pas autorisé à afficher le diagramme" | "Não está autorizado a visualizar o diagrama" | "Non sei abilitato a visualizzare il diagramma";
760
766
  static get WorkflowEndInstance(): "Instanz beenden" | "End instance" | "Finalizar instancia" | "Termine l'instance" | "Pare a instância" | "Termina istanza";
@@ -494,6 +494,16 @@ export class SDKUI_Localizator {
494
494
  default: return "Argomenti";
495
495
  }
496
496
  }
497
+ static get AssignTo() {
498
+ switch (this._cultureID) {
499
+ case CultureIDs.De_DE: return "Zuweisen an";
500
+ case CultureIDs.En_US: return "Assign to";
501
+ case CultureIDs.Es_ES: return "Asignar a";
502
+ case CultureIDs.Fr_FR: return "Assigner à";
503
+ case CultureIDs.Pt_PT: return "Atribuir a";
504
+ default: return "Assegna a";
505
+ }
506
+ }
497
507
  static get AssignedBy() {
498
508
  switch (this._cultureID) {
499
509
  case CultureIDs.De_DE: return "Zugewiesen von";
@@ -4258,6 +4268,16 @@ export class SDKUI_Localizator {
4258
4268
  default: return "Nessun risultato trovato";
4259
4269
  }
4260
4270
  }
4271
+ static get NoSignatureFound() {
4272
+ switch (this._cultureID) {
4273
+ case CultureIDs.De_DE: return "Keine Unterschrift gefunden";
4274
+ case CultureIDs.En_US: return "No signature found";
4275
+ case CultureIDs.Es_ES: return "No se encontró ninguna firma";
4276
+ case CultureIDs.Fr_FR: return "Aucune signature trouvée";
4277
+ case CultureIDs.Pt_PT: return "Nenhuma assinatura encontrada";
4278
+ default: return "Nessuna firma trovata";
4279
+ }
4280
+ }
4261
4281
  static get NoSource() {
4262
4282
  switch (this._cultureID) {
4263
4283
  case CultureIDs.De_DE: return "Keine Quelle";
@@ -7496,42 +7516,82 @@ export class SDKUI_Localizator {
7496
7516
  }
7497
7517
  static get WorkflowDiagramConditionTwoOutgoing() {
7498
7518
  switch (this._cultureID) {
7499
- case CultureIDs.De_DE: return "L'elemento 'Condition' deve avere esattamente due connessioni in uscita.";
7500
- case CultureIDs.En_US: return "The 'Condition' item must have exactly two outgoing connections.";
7501
- case CultureIDs.Es_ES: return "El elemento 'Condition' debe tener exactamente dos conexiones de salida.";
7502
- case CultureIDs.Fr_FR: return "L'élément 'Condition' doit avoir exactement deux connexions sortantes.";
7503
- case CultureIDs.Pt_PT: return "O elemento 'Condition' deve ter exactamente duas ligações de saída.";
7504
- default: return "L'elemento 'Condition' deve avere esattamente due connessioni in uscita.";
7519
+ case CultureIDs.De_DE: return "L'elemento '{{0}}' deve avere esattamente due connessioni in uscita.";
7520
+ case CultureIDs.En_US: return "The '{{0}}' item must have exactly two outgoing connections.";
7521
+ case CultureIDs.Es_ES: return "El elemento '{{0}}' debe tener exactamente dos conexiones de salida.";
7522
+ case CultureIDs.Fr_FR: return "L'élément '{{0}}' doit avoir exactement deux connexions sortantes.";
7523
+ case CultureIDs.Pt_PT: return "O elemento '{{0}}' deve ter exactamente duas ligações de saída.";
7524
+ default: return "L'elemento '{{0}}' deve avere esattamente due connessioni in uscita.";
7505
7525
  }
7506
7526
  }
7507
7527
  static get WorkflowDiagramConditionMustHaveIncoming() {
7508
7528
  switch (this._cultureID) {
7509
- case CultureIDs.De_DE: return "L'elemento 'Condition' deve avere almeno una connessione in ingresso.";
7510
- case CultureIDs.En_US: return "The 'Condition' item must have at least one incoming connection.";
7511
- case CultureIDs.Es_ES: return "El elemento 'Condition' debe tener al menos una conexión de entrada.";
7512
- case CultureIDs.Fr_FR: return "L'élément 'Condition' doit avoir au moins une connexion entrante.";
7513
- case CultureIDs.Pt_PT: return "O elemento 'Condition' deve ter pelo menos uma ligação de entrada.";
7514
- default: return "L'elemento 'Condition' deve avere almeno una connessione in ingresso.";
7529
+ case CultureIDs.De_DE: return "L'elemento '{{0}}' deve avere almeno una connessione in ingresso.";
7530
+ case CultureIDs.En_US: return "The '{{0}}' item must have at least one incoming connection.";
7531
+ case CultureIDs.Es_ES: return "El elemento '{{0}}' debe tener al menos una conexión de entrada.";
7532
+ case CultureIDs.Fr_FR: return "L'élément '{{0}}' doit avoir au moins une connexion entrante.";
7533
+ case CultureIDs.Pt_PT: return "O elemento '{{0}}' deve ter pelo menos uma ligação de entrada.";
7534
+ default: return "L'elemento '{{0}}' deve avere almeno una connessione in ingresso.";
7515
7535
  }
7516
7536
  }
7517
7537
  static get WorkflowDiagramElementShouldHaveTwoOutgoing() {
7518
7538
  switch (this._cultureID) {
7519
- case CultureIDs.De_DE: return "L'elemento '{0}' dovrebbe avere esattamente due connessioni in uscita.";
7520
- case CultureIDs.En_US: return "The element '{0}' should have exactly two outgoing connections.";
7521
- case CultureIDs.Es_ES: return "El elemento '{0}' debería tener exactamente dos conexiones de salida.";
7522
- case CultureIDs.Fr_FR: return "L'élément '{0}' devrait avoir exactement deux connexions sortantes.";
7523
- case CultureIDs.Pt_PT: return "O elemento '{0}' deveria ter exactamente duas ligações de saída.";
7524
- default: return "L'elemento '{0}' dovrebbe avere esattamente due connessioni in uscita.";
7539
+ case CultureIDs.De_DE: return "L'elemento '{{0}}' dovrebbe avere esattamente due connessioni in uscita.";
7540
+ case CultureIDs.En_US: return "The element '{{0}}' should have exactly two outgoing connections.";
7541
+ case CultureIDs.Es_ES: return "El elemento '{{0}}' debería tener exactamente dos conexiones de salida.";
7542
+ case CultureIDs.Fr_FR: return "L'élément '{{0}}' devrait avoir exactement deux connexions sortantes.";
7543
+ case CultureIDs.Pt_PT: return "O elemento '{{0}}' deveria ter exactamente duas ligações de saída.";
7544
+ default: return "L'elemento '{{0}}' dovrebbe avere esattamente due connessioni in uscita.";
7525
7545
  }
7526
7546
  }
7527
7547
  static get WorkflowDiagramElementShouldHaveIncoming() {
7528
7548
  switch (this._cultureID) {
7529
- case CultureIDs.De_DE: return "L'elemento '{0}' deve avere almeno una connessione in ingresso.";
7530
- case CultureIDs.En_US: return "The element '{0}' must have at least one incoming connection.";
7531
- case CultureIDs.Es_ES: return "El elemento '{0}' debe tener al menos una conexión de entrada.";
7532
- case CultureIDs.Fr_FR: return "L'élément '{0}' doit avoir au moins une connexion entrante.";
7533
- case CultureIDs.Pt_PT: return "O elemento '{0}' deve ter pelo menos uma ligação de entrada.";
7534
- default: return "L'elemento '{0}' deve avere almeno una connessione in ingresso.";
7549
+ case CultureIDs.De_DE: return "L'elemento '{{0}}' deve avere almeno una connessione in ingresso.";
7550
+ case CultureIDs.En_US: return "The element '{{0}}' must have at least one incoming connection.";
7551
+ case CultureIDs.Es_ES: return "El elemento '{{0}}' debe tener al menos una conexión de entrada.";
7552
+ case CultureIDs.Fr_FR: return "L'élément '{{0}}' doit avoir au moins une connexion entrante.";
7553
+ case CultureIDs.Pt_PT: return "O elemento '{{0}}' deve ter pelo menos uma ligação de entrada.";
7554
+ default: return "L'elemento '{{0}}' deve avere almeno una connessione in ingresso.";
7555
+ }
7556
+ }
7557
+ static get WorkflowDiagramElementMustHaveIncoming() {
7558
+ switch (this._cultureID) {
7559
+ case CultureIDs.De_DE: return "Das Element '{{0}}' muss mindestens eine eingehende Verbindung haben.";
7560
+ case CultureIDs.En_US: return "The element '{{0}}' must have at least one incoming connection.";
7561
+ case CultureIDs.Es_ES: return "El elemento '{{0}}' debe tener al menos una conexión de entrada.";
7562
+ case CultureIDs.Fr_FR: return "L'élément '{{0}}' doit avoir au moins une connexion entrante.";
7563
+ case CultureIDs.Pt_PT: return "O elemento '{{0}}' deve ter pelo menos uma ligação de entrada.";
7564
+ default: return "L'elemento '{{0}}' deve avere almeno una connessione in ingresso.";
7565
+ }
7566
+ }
7567
+ static get WorkflowDiagramElementCannotHaveOutgoing() {
7568
+ switch (this._cultureID) {
7569
+ case CultureIDs.De_DE: return "Das Element '{{0}}' kann keine ausgehenden Verbindungen haben.";
7570
+ case CultureIDs.En_US: return "The element '{{0}}' cannot have outgoing connections.";
7571
+ case CultureIDs.Es_ES: return "El elemento '{{0}}' no puede tener conexiones de salida.";
7572
+ case CultureIDs.Fr_FR: return "L'élément '{{0}}' ne peut pas avoir de connexions sortantes.";
7573
+ case CultureIDs.Pt_PT: return "O elemento '{{0}}' não pode ter ligações de saída.";
7574
+ default: return "L'elemento '{{0}}' non può avere connessioni in uscita.";
7575
+ }
7576
+ }
7577
+ static get WorkflowDiagramElementShouldHaveOutgoing() {
7578
+ switch (this._cultureID) {
7579
+ case CultureIDs.De_DE: return "Das Element '{{0}}' sollte mindestens eine ausgehende Verbindung haben.";
7580
+ case CultureIDs.En_US: return "The element '{{0}}' should have at least one outgoing connection.";
7581
+ case CultureIDs.Es_ES: return "El elemento '{{0}}' debería tener al menos una conexión de salida.";
7582
+ case CultureIDs.Fr_FR: return "L'élément '{{0}}' devrait avoir au moins une connexion sortante.";
7583
+ case CultureIDs.Pt_PT: return "O elemento '{{0}}' deveria ter pelo menos uma ligação de saída.";
7584
+ default: return "L'elemento '{{0}}' dovrebbe avere almeno una connessione in uscita.";
7585
+ }
7586
+ }
7587
+ static get WorkflowDiagramElementShouldHaveOneOutgoing() {
7588
+ switch (this._cultureID) {
7589
+ case CultureIDs.De_DE: return "Das Element '{{0}}' sollte genau eine ausgehende Verbindung haben.";
7590
+ case CultureIDs.En_US: return "The element '{{0}}' should have exactly one outgoing connection.";
7591
+ case CultureIDs.Es_ES: return "El elemento '{{0}}' debería tener exactamente una conexión de salida.";
7592
+ case CultureIDs.Fr_FR: return "L'élément '{{0}}' devrait avoir exactement une connexion sortante.";
7593
+ case CultureIDs.Pt_PT: return "O elemento '{{0}}' deveria ter exactamente uma ligação de saída.";
7594
+ default: return "L'elemento '{{0}}' dovrebbe avere esattamente una connessione in uscita.";
7535
7595
  }
7536
7596
  }
7537
7597
  static get WorkflowDiagramMissingOrInvalid() {
@@ -21,6 +21,7 @@ export declare const isPdfEditorEnabled: (widgetsString: string) => boolean;
21
21
  export declare const isPdfEditorAvailable: (fromDTD: DcmtTypeDescriptor | undefined, ext: string | undefined) => boolean;
22
22
  interface TabItemProps {
23
23
  $isSelected: boolean;
24
+ $activeGradient?: string;
24
25
  }
25
26
  export declare const StyledTabItem: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components/dist/types").Substitute<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, TabItemProps>> & string;
26
27
  export declare const StyledTabIcon: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components/dist/types").Substitute<React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>, TabItemProps>> & string;
@@ -194,8 +194,9 @@ export const StyledTabItem = styled.div `
194
194
  border-radius: 8px;
195
195
  font-weight: ${({ $isSelected }) => ($isSelected ? 'bold' : 'normal')};
196
196
  color: ${({ $isSelected }) => ($isSelected ? '#fff' : '#000')};
197
- background: ${({ $isSelected }) => $isSelected
198
- ? 'linear-gradient(270deg, #46B5A2 16%, #3BAABC 34%, #3BAABC 34%, #3681AD 54%, #3368A5 72%, #2F549D 88%, #304F99 100%)'
197
+ background: ${({ $isSelected, $activeGradient }) => $isSelected
198
+ ? ($activeGradient ??
199
+ 'linear-gradient(270deg, #46B5A2 16%, #3BAABC 34%, #3BAABC 34%, #3681AD 54%, #3368A5 72%, #2F549D 88%, #304F99 100%)')
199
200
  : 'transparent'};
200
201
  transition: background-color 0.2s ease;
201
202
  font-size: 1rem;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@topconsultnpm/sdkui-react",
3
- "version": "6.20.0-dev3.12",
3
+ "version": "6.20.0-dev3.14",
4
4
  "description": "",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\" && exit 1",