@topconsultnpm/sdkui-react 6.20.0-test1 → 6.20.0

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 (109) hide show
  1. package/lib/components/NewComponents/ContextMenu/styles.d.ts +3 -1
  2. package/lib/components/NewComponents/ContextMenu/styles.js +7 -5
  3. package/lib/components/base/Styled.d.ts +4 -1
  4. package/lib/components/base/Styled.js +11 -3
  5. package/lib/components/base/TMPanel.js +6 -4
  6. package/lib/components/base/TMPopUp.js +4 -0
  7. package/lib/components/base/TMTreeView.d.ts +3 -1
  8. package/lib/components/base/TMTreeView.js +68 -21
  9. package/lib/components/choosers/TMDataListItemChooser.js +1 -1
  10. package/lib/components/choosers/TMDataListItemEditor.d.ts +11 -0
  11. package/lib/components/choosers/TMDataListItemEditor.js +130 -0
  12. package/lib/components/choosers/TMDataListItemFields.d.ts +11 -0
  13. package/lib/components/choosers/TMDataListItemFields.js +61 -0
  14. package/lib/components/choosers/TMDataListItemPicker.d.ts +2 -0
  15. package/lib/components/choosers/TMDataListItemPicker.js +182 -18
  16. package/lib/components/choosers/TMDynDataListItemChooser.js +11 -6
  17. package/lib/components/choosers/TMImageIDChooser.d.ts +16 -0
  18. package/lib/components/choosers/TMImageIDChooser.js +53 -0
  19. package/lib/components/choosers/TMMetadataChooser.js +1 -1
  20. package/lib/components/choosers/TMUserChooser.js +1 -1
  21. package/lib/components/editors/TMDateBox.js +1 -1
  22. package/lib/components/editors/TMHtmlEditor.js +1 -1
  23. package/lib/components/editors/TMLocalizedTextBox.d.ts +1 -0
  24. package/lib/components/editors/TMLocalizedTextBox.js +3 -3
  25. package/lib/components/editors/TMMetadataValues.js +203 -41
  26. package/lib/components/editors/TMTextArea.d.ts +1 -0
  27. package/lib/components/editors/TMTextArea.js +6 -6
  28. package/lib/components/editors/TMTextBox.js +9 -10
  29. package/lib/components/features/archive/TMArchive.d.ts +3 -1
  30. package/lib/components/features/archive/TMArchive.js +31 -44
  31. package/lib/components/features/blog/TMBlogCommentForm.d.ts +3 -0
  32. package/lib/components/features/blog/TMBlogCommentForm.js +42 -36
  33. package/lib/components/features/documents/TMDcmtForm.d.ts +3 -1
  34. package/lib/components/features/documents/TMDcmtForm.js +215 -54
  35. package/lib/components/features/documents/TMDcmtPreview.js +66 -13
  36. package/lib/components/features/documents/TMDcmtTasks.d.ts +3 -1
  37. package/lib/components/features/documents/TMDcmtTasks.js +2 -2
  38. package/lib/components/features/documents/TMFileUploader.d.ts +5 -0
  39. package/lib/components/features/documents/TMFileUploader.js +28 -6
  40. package/lib/components/features/documents/TMMasterDetailDcmts.js +31 -85
  41. package/lib/components/features/documents/TMRelationViewer.d.ts +7 -1
  42. package/lib/components/features/documents/TMRelationViewer.js +497 -111
  43. package/lib/components/features/search/TMSearchQueryPanel.js +6 -6
  44. package/lib/components/features/search/TMSearchResult.d.ts +2 -0
  45. package/lib/components/features/search/TMSearchResult.js +106 -86
  46. package/lib/components/features/search/TMSearchResultsMenuItems.d.ts +1 -1
  47. package/lib/components/features/search/TMSearchResultsMenuItems.js +6 -18
  48. package/lib/components/features/search/TMSignatureInfoContent.js +10 -6
  49. package/lib/components/features/search/TMTreeSelector.js +1 -1
  50. package/lib/components/features/tasks/TMTaskForm.d.ts +1 -0
  51. package/lib/components/features/tasks/TMTaskForm.js +61 -193
  52. package/lib/components/features/tasks/TMTaskFormUtils.d.ts +80 -0
  53. package/lib/components/features/tasks/TMTaskFormUtils.js +559 -0
  54. package/lib/components/features/tasks/TMTasksUtils.d.ts +3 -1
  55. package/lib/components/features/tasks/TMTasksUtils.js +46 -16
  56. package/lib/components/features/tasks/TMTasksUtilsView.d.ts +0 -7
  57. package/lib/components/features/tasks/TMTasksUtilsView.js +7 -14
  58. package/lib/components/features/tasks/TMTasksView.js +5 -3
  59. package/lib/components/features/workflow/TMWorkflowPopup.d.ts +20 -3
  60. package/lib/components/features/workflow/TMWorkflowPopup.js +21 -109
  61. package/lib/components/features/workflow/diagram/ConnectionComponent.d.ts +1 -0
  62. package/lib/components/features/workflow/diagram/ConnectionComponent.js +6 -2
  63. package/lib/components/features/workflow/diagram/DiagramItemForm.d.ts +2 -0
  64. package/lib/components/features/workflow/diagram/DiagramItemForm.js +32 -25
  65. package/lib/components/features/workflow/diagram/RecipientList.d.ts +3 -1
  66. package/lib/components/features/workflow/diagram/RecipientList.js +13 -9
  67. package/lib/components/features/workflow/diagram/WFDiagram.js +102 -5
  68. package/lib/components/features/workflow/diagram/workflowHelpers.js +31 -19
  69. package/lib/components/forms/Login/TMLoginForm.js +1 -1
  70. package/lib/components/forms/TMSaveForm.js +61 -13
  71. package/lib/components/grids/TMBlogsPost.js +8 -8
  72. package/lib/components/grids/TMBlogsPostUtils.js +2 -2
  73. package/lib/components/grids/TMRecentsManager.js +1 -1
  74. package/lib/components/index.d.ts +2 -0
  75. package/lib/components/index.js +2 -0
  76. package/lib/components/layout/panelManager/TMPanelManagerContainer.js +3 -2
  77. package/lib/components/pages/TMPage.js +4 -0
  78. package/lib/components/query/TMQueryEditor.d.ts +1 -0
  79. package/lib/components/query/TMQueryEditor.js +3 -3
  80. package/lib/components/viewers/TMMidViewer.js +2 -1
  81. package/lib/components/viewers/TMTidViewer.js +7 -3
  82. package/lib/helper/Enum_Localizator.js +5 -0
  83. package/lib/helper/GlobalStyles.js +3 -0
  84. package/lib/helper/SDKUI_Globals.d.ts +12 -0
  85. package/lib/helper/SDKUI_Globals.js +21 -1
  86. package/lib/helper/SDKUI_Localizator.d.ts +31 -7
  87. package/lib/helper/SDKUI_Localizator.js +286 -46
  88. package/lib/helper/TMIcons.d.ts +2 -1
  89. package/lib/helper/TMIcons.js +4 -1
  90. package/lib/helper/TMUtils.d.ts +33 -41
  91. package/lib/helper/TMUtils.js +157 -170
  92. package/lib/helper/helpers.d.ts +6 -2
  93. package/lib/helper/helpers.js +24 -8
  94. package/lib/helper/index.d.ts +1 -0
  95. package/lib/helper/index.js +1 -0
  96. package/lib/helper/queryHelper.js +1 -1
  97. package/lib/hooks/useBetaFeatures.d.ts +1 -0
  98. package/lib/hooks/useBetaFeatures.js +41 -0
  99. package/lib/hooks/useDataUserIdItem.js +2 -2
  100. package/lib/hooks/useDcmtOperations.js +14 -2
  101. package/lib/hooks/useRelatedDocuments.js +64 -42
  102. package/lib/index.d.ts +1 -0
  103. package/lib/index.js +1 -0
  104. package/lib/services/platform_services.d.ts +1 -1
  105. package/lib/services/platform_services.js +4 -0
  106. package/lib/ts/types.d.ts +3 -0
  107. package/package.json +2 -2
  108. package/lib/components/features/search/TMSignSettingsForm.d.ts +0 -9
  109. package/lib/components/features/search/TMSignSettingsForm.js +0 -621
@@ -10,7 +10,7 @@ import TMTextBox from '../../../editors/TMTextBox';
10
10
  import TMButton from '../../../base/TMButton';
11
11
  import styled from 'styled-components';
12
12
  import TMQuerySummary from '../../../query/TMQuerySummary';
13
- import { CultureIDs, DcmtTypeListCacheService, FromItem, MetadataDataDomains, SDK_Globals, SearchEngine, Severities, WFAppTypes, WorkItemSetRules } from '@topconsultnpm/sdk-ts';
13
+ import { CultureIDs, DcmtTypeListCacheService, FromItem, MetadataDataDomains, ResultTypes, SDK_Globals, SearchEngine, Severities, WFAppTypes, WorkItemSetRules } from '@topconsultnpm/sdk-ts';
14
14
  import TMLocalizedTextBox from '../../../editors/TMLocalizedTextBox';
15
15
  import TMDataListItemPicker from '../../../choosers/TMDataListItemPicker';
16
16
  import WorkitemRecipientsEditor, { actorsToTos, RecipientsContainer, tosToActors } from './WorkitemRecipientsEditor';
@@ -30,9 +30,16 @@ import { DiagramItemProps, wfDiagramItemValidator } from './workflowHelpers';
30
30
  const FormContainer = styled.div `
31
31
  display: flex;
32
32
  flex-direction: column;
33
- gap: 5px;
33
+ height: 100%;
34
34
  padding: 10px;
35
35
  `;
36
+ const FieldsContainer = styled.div `
37
+ display: flex;
38
+ flex-direction: column;
39
+ gap: 5px;
40
+ flex: 1;
41
+ overflow-y: auto;
42
+ `;
36
43
  const FlexContainer = styled.div `
37
44
  display: flex;
38
45
  align-items: center;
@@ -76,7 +83,7 @@ const APP_TYPES_DATASOURCE = [
76
83
  { value: WFAppTypes.SP, display: "SP" },
77
84
  { value: WFAppTypes.REST, display: "REST" }
78
85
  ];
79
- const DiagramItemForm = ({ itemToEdit, wf, onClose, onApply }) => {
86
+ const DiagramItemForm = ({ itemToEdit, wf, onClose, onApply, onStatusItemEdited }) => {
80
87
  const [localItem, setLocalItem] = useState(itemToEdit);
81
88
  const [localItemOrig] = useState(structuredClone(itemToEdit));
82
89
  const [validationItems, setValidationItems] = useState([]);
@@ -392,7 +399,7 @@ const DiagramItemForm = ({ itemToEdit, wf, onClose, onApply }) => {
392
399
  };
393
400
  // Function to render Status-specific fields
394
401
  const renderStatusFields = () => {
395
- return (_jsx(TMDataListItemPicker, { dataListID: wf?.MStatusDLID, selectedValue: localItem.StatusValue, onItemSelect: handleStatusChange }));
402
+ return (_jsx(TMDataListItemPicker, { dataListID: wf?.MStatusDLID, selectedValue: localItem.StatusValue, onItemSelect: handleStatusChange, onItemEdited: onStatusItemEdited, allowEdit: true }));
396
403
  };
397
404
  const renderAppFields = () => {
398
405
  return (_jsxs(_Fragment, { children: [_jsx(TMDropDown, { label: SDKUI_Localizator.WorkflowAppType, dataSource: APP_TYPES_DATASOURCE, value: localItem.AppType, isModifiedWhen: localItem.AppType !== localItemOrig.AppType, validationItems: validationItems.filter(v => v.PropertyName === DiagramItemProps.AppType), onValueChanged: (e) => { handleAppTypeChange(e.target.value); } }), localItem.AppType === WFAppTypes.EXE
@@ -580,38 +587,38 @@ const DiagramItemForm = ({ itemToEdit, wf, onClose, onApply }) => {
580
587
  setDossierTypes(formattedList);
581
588
  });
582
589
  }, [localItem.Type]);
583
- // Gestione di Tos e Tos2
584
- const { andRecipients: tosRecipients } = useMemo(() => {
585
- return tosToActors(localItem.Tos ?? '');
586
- }, [localItem.Tos]);
587
- const { andRecipients: tos2Recipients } = useMemo(() => {
590
+ // Owner = Tos2, Participants = Tos
591
+ const { andRecipients: ownerRecipients } = useMemo(() => {
588
592
  return tosToActors(localItem.Tos2 ?? '');
589
593
  }, [localItem.Tos2]);
590
- const handleAddTosRecipients = useCallback((newRecipients, orValue) => {
591
- const { andRecipients } = tosToActors(localItem.Tos ?? '');
592
- const updatedRecipients = [...andRecipients, ...newRecipients.map(r => ({ ...r, Or: orValue }))];
593
- const newTos = actorsToTos(updatedRecipients);
594
- handleTosChange(newTos);
595
- }, [localItem.Tos, handleTosChange]);
596
- const handleRemoveTosRecipient = useCallback((recipientToRemove) => {
597
- const { andRecipients } = tosToActors(localItem.Tos ?? '');
598
- const updatedRecipients = andRecipients.filter(r => r.ActorType !== recipientToRemove.ActorType || r.ActorID !== recipientToRemove.ActorID);
599
- const newTos = actorsToTos(updatedRecipients);
600
- handleTosChange(newTos);
601
- }, [localItem.Tos, handleTosChange]);
602
- const handleAddTos2Recipients = useCallback((newRecipients, orValue) => {
594
+ const { andRecipients: participantRecipients } = useMemo(() => {
595
+ return tosToActors(localItem.Tos ?? '');
596
+ }, [localItem.Tos]);
597
+ const handleAddOwnerRecipients = useCallback((newRecipients, orValue) => {
603
598
  const { andRecipients } = tosToActors(localItem.Tos2 ?? '');
604
599
  const updatedRecipients = [...andRecipients, ...newRecipients.map(r => ({ ...r, Or: orValue }))];
605
600
  const newTos = actorsToTos(updatedRecipients);
606
601
  handleTos2Change(newTos);
607
602
  }, [localItem.Tos2, handleTos2Change]);
608
- const handleRemoveTos2Recipient = useCallback((recipientToRemove) => {
603
+ const handleRemoveOwnerRecipient = useCallback((recipientToRemove) => {
609
604
  const { andRecipients } = tosToActors(localItem.Tos2 ?? '');
610
605
  const updatedRecipients = andRecipients.filter(r => r.ActorType !== recipientToRemove.ActorType || r.ActorID !== recipientToRemove.ActorID);
611
606
  const newTos = actorsToTos(updatedRecipients);
612
607
  handleTos2Change(newTos);
613
608
  }, [localItem.Tos2, handleTos2Change]);
614
- return (_jsxs(_Fragment, { children: [_jsx(TMTextExpression, { label: `${SDKUI_Localizator.Name} (${SDKUI_Localizator.Dossier})`, value: localItem.PlatformObjName, valueOrig: localItemOrig.PlatformObjName, tid: wf?.MTID, isModifiedWhen: (localItem.PlatformObjName ?? '') !== (localItemOrig.PlatformObjName ?? ''), onValueChanged: handlePlatformObjNameChange }), _jsx(TMDropDown, { dataSource: dossierTypes, label: `${SDKUI_Localizator.Description} (${SDKUI_Localizator.Dossier})`, value: localItem.Value3asInt, isModifiedWhen: (localItem.Value3asInt ?? 0) !== (localItemOrig.Value3asInt ?? 0), onValueChanged: (e) => { handleValue3asIntChange(e.target.value); } }), _jsx(TMTextExpression, { label: `${SDKUI_Localizator.Description} (${SDKUI_Localizator.Dossier})`, value: localItem.PlatformObjDescr, valueOrig: localItemOrig.PlatformObjDescr, tid: wf?.MTID, isModifiedWhen: (localItem.PlatformObjDescr ?? '') !== (localItemOrig.PlatformObjDescr ?? ''), onValueChanged: handlePlatformObjDescrChange }), _jsx(TMCultureIDPicker, { label: SDKUI_Localizator.Format, selectedValue: localItem.FormatCultureID, isModifiedWhen: localItem.FormatCultureID !== localItemOrig.FormatCultureID, openChooserBySingleClick: true, onSelectCultureID: handleFormatCultureIDChange }), _jsx(TMTextExpression, { label: `${SDKUI_Localizator.CommentText} (${SDKUI_Localizator.BlogCase})`, placeHolder: 'Inserisci il valore', rows: 2, value: localItem.Value1asString, valueOrig: localItemOrig.Value1asString, tid: wf?.MTID, isModifiedWhen: (localItem.Value1asString ?? '') !== (localItemOrig.Value1asString ?? ''), onValueChanged: handleValue1asStringChange }), _jsx(TMCheckBox, { value: localItem.Value1asInt ?? 0, label: SDKUI_Localizator.WorkflowAddDcmtAsAttachment, isModifiedWhen: localItem.Value1asInt !== localItemOrig.Value1asInt, onValueChanged: handleValue1asIntChange }), _jsx(TMCheckBox, { value: localItem.Value2asInt ?? 0, label: SDKUI_Localizator.WorkflowAddDcmtToDossier, isModifiedWhen: localItem.Value2asInt !== localItemOrig.Value2asInt, onValueChanged: handleValue2asIntChange }), _jsx(TMCheckBox, { value: localItem.Trunc ?? 0, label: SDKUI_Localizator.TruncateString, isModifiedWhen: localItem.Trunc !== localItemOrig.Trunc, onValueChanged: handleTruncChange }), _jsxs(RecipientsContainer, { children: [_jsx(RecipientList, { recipients: tosRecipients, title: SDKUI_Localizator.OwnerName, tid: wf?.MTID, onAdd: (newRecipients) => handleAddTosRecipients(newRecipients, 0), onRemove: handleRemoveTosRecipient }), _jsx(RecipientList, { recipients: tos2Recipients, title: SDKUI_Localizator.Participants, tid: wf?.MTID, onAdd: (newRecipients) => handleAddTos2Recipients(newRecipients, 0), onRemove: handleRemoveTos2Recipient })] })] }));
609
+ const handleAddParticipantRecipients = useCallback((newRecipients, orValue) => {
610
+ const { andRecipients } = tosToActors(localItem.Tos ?? '');
611
+ const updatedRecipients = [...andRecipients, ...newRecipients.map(r => ({ ...r, Or: orValue }))];
612
+ const newTos = actorsToTos(updatedRecipients);
613
+ handleTosChange(newTos);
614
+ }, [localItem.Tos, handleTosChange]);
615
+ const handleRemoveParticipantRecipient = useCallback((recipientToRemove) => {
616
+ const { andRecipients } = tosToActors(localItem.Tos ?? '');
617
+ const updatedRecipients = andRecipients.filter(r => r.ActorType !== recipientToRemove.ActorType || r.ActorID !== recipientToRemove.ActorID);
618
+ const newTos = actorsToTos(updatedRecipients);
619
+ handleTosChange(newTos);
620
+ }, [localItem.Tos, handleTosChange]);
621
+ return (_jsxs(_Fragment, { children: [_jsx(TMTextExpression, { label: `${SDKUI_Localizator.Name} (${SDKUI_Localizator.Dossier})`, value: localItem.PlatformObjName, valueOrig: localItemOrig.PlatformObjName, tid: wf?.MTID, isModifiedWhen: (localItem.PlatformObjName ?? '') !== (localItemOrig.PlatformObjName ?? ''), onValueChanged: handlePlatformObjNameChange }), _jsx(TMDropDown, { dataSource: dossierTypes, label: SDKUI_Localizator.DossierType, value: localItem.Value3asInt, isModifiedWhen: (localItem.Value3asInt ?? 0) !== (localItemOrig.Value3asInt ?? 0), onValueChanged: (e) => { handleValue3asIntChange(e.target.value); } }), _jsx(TMTextExpression, { label: `${SDKUI_Localizator.Description} (${SDKUI_Localizator.Dossier})`, value: localItem.PlatformObjDescr, valueOrig: localItemOrig.PlatformObjDescr, tid: wf?.MTID, isModifiedWhen: (localItem.PlatformObjDescr ?? '') !== (localItemOrig.PlatformObjDescr ?? ''), onValueChanged: handlePlatformObjDescrChange }), _jsx(TMCultureIDPicker, { label: SDKUI_Localizator.Format, selectedValue: localItem.FormatCultureID, isModifiedWhen: localItem.FormatCultureID !== localItemOrig.FormatCultureID, openChooserBySingleClick: true, onSelectCultureID: handleFormatCultureIDChange }), _jsx(TMTextExpression, { label: `${SDKUI_Localizator.CommentText} (${SDKUI_Localizator.BlogCase})`, placeHolder: 'Inserisci il valore', rows: 2, value: localItem.Value1asString, valueOrig: localItemOrig.Value1asString, tid: wf?.MTID, isModifiedWhen: (localItem.Value1asString ?? '') !== (localItemOrig.Value1asString ?? ''), onValueChanged: handleValue1asStringChange }), _jsx(TMCheckBox, { value: localItem.Value1asInt ?? 0, label: SDKUI_Localizator.WorkflowAddDcmtAsAttachment, isModifiedWhen: localItem.Value1asInt !== localItemOrig.Value1asInt, onValueChanged: handleValue1asIntChange }), _jsx(TMCheckBox, { value: localItem.Value2asInt ?? 0, label: SDKUI_Localizator.WorkflowAddDcmtToDossier, isModifiedWhen: localItem.Value2asInt !== localItemOrig.Value2asInt, onValueChanged: handleValue2asIntChange }), _jsx(TMCheckBox, { value: localItem.Trunc ?? 0, label: SDKUI_Localizator.TruncateString, isModifiedWhen: localItem.Trunc !== localItemOrig.Trunc, onValueChanged: handleTruncChange }), _jsxs(RecipientsContainer, { children: [_jsx(RecipientList, { recipients: ownerRecipients, title: SDKUI_Localizator.OwnerName, tid: wf?.MTID, maxRecipients: 1, validationItems: validationItems.filter(v => v.PropertyName === DiagramItemProps.Tos2), onAdd: (newRecipients) => handleAddOwnerRecipients(newRecipients, 0), onRemove: handleRemoveOwnerRecipient }), _jsx(RecipientList, { recipients: participantRecipients, title: SDKUI_Localizator.Participants, tid: wf?.MTID, onAdd: (newRecipients) => handleAddParticipantRecipients(newRecipients, 0), onRemove: handleRemoveParticipantRecipient })] })] }));
615
622
  };
616
623
  const renderAddPartsFields = () => {
617
624
  const { andRecipients: tosRecipients } = useMemo(() => {
@@ -679,7 +686,7 @@ const DiagramItemForm = ({ itemToEdit, wf, onClose, onApply }) => {
679
686
  default:
680
687
  specificFields = null;
681
688
  }
682
- return (_jsxs(FormContainer, { children: [renderCommonFields(), specificFields, _jsxs(ButtonsContainer, { children: [_jsx(TMButton, { caption: 'Applica', btnStyle: 'advanced', advancedColor: TMColors.tertiary, icon: _jsx(IconApply, {}), showTooltip: false, disabled: !isModified, onClick: handleSave }), _jsx(TMButton, { caption: 'Annulla', btnStyle: 'toolbar', color: 'primary', icon: _jsx(IconUndo, {}), showTooltip: false, disabled: !isModified, onClick: handleCancel })] })] }));
689
+ return (_jsxs(FormContainer, { children: [_jsxs(FieldsContainer, { children: [renderCommonFields(), specificFields] }), _jsxs(ButtonsContainer, { children: [_jsx(TMButton, { caption: 'Applica', btnStyle: 'advanced', advancedColor: TMColors.tertiary, icon: _jsx(IconApply, {}), showTooltip: false, disabled: !isModified || validationItems.some(v => v.ResultType === ResultTypes.ERROR), onClick: handleSave }), _jsx(TMButton, { caption: 'Annulla', btnStyle: 'toolbar', color: 'primary', icon: _jsx(IconUndo, {}), showTooltip: false, disabled: !isModified, onClick: handleCancel })] })] }));
683
690
  };
684
691
  return (_jsx(TMModal, { title: LocalizeDiagramItemType(localItem.Type), onClose: onClose, isModal: true, width: calculatedWidth, height: calculatedHeight, children: renderForm() }));
685
692
  };
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { QueryDescriptor } from '@topconsultnpm/sdk-ts';
2
+ import { QueryDescriptor, ValidationItem } from '@topconsultnpm/sdk-ts';
3
3
  export declare enum WorkItemActorTypes {
4
4
  None = 0,
5
5
  UID = 1,
@@ -19,6 +19,8 @@ interface RecipientListProps {
19
19
  title: string;
20
20
  tid?: number;
21
21
  qd?: QueryDescriptor;
22
+ maxRecipients?: number;
23
+ validationItems?: ValidationItem[];
22
24
  onQDChange?: (newQd: QueryDescriptor | undefined) => void;
23
25
  onAdd: (recipient: WorkItemActor[]) => void;
24
26
  onRemove: (recipient: WorkItemActor) => void;
@@ -7,6 +7,7 @@ import { TMUserChooserForm } from '../../../choosers/TMUserChooser';
7
7
  import { TMGroupChooserForm, TMGroupIdViewer } from '../../../choosers/TMGroupChooser';
8
8
  import { TMMidViewer } from '../../../viewers/TMMidViewer';
9
9
  import { SDK_Globals, SDK_Localizator } from '@topconsultnpm/sdk-ts';
10
+ import TMVilViewer from '../../../base/TMVilViewer';
10
11
  import { useOutsideClick } from '../../../../hooks/useOutsideClick';
11
12
  import { FormModes } from '../../../../ts';
12
13
  import { TMMessageBoxManager, ButtonNames } from '../../../base/TMPopUp';
@@ -70,7 +71,7 @@ const FloatingMenu = styled.div `
70
71
  const FloatingMenuButton = (props) => {
71
72
  return _jsx(TMButton, { width: "100%", ...props });
72
73
  };
73
- const RecipientList = ({ recipients, title, tid, qd, onAdd, onRemove, onQDChange }) => {
74
+ const RecipientList = ({ recipients, title, tid, qd, maxRecipients, validationItems, onAdd, onRemove, onQDChange }) => {
74
75
  const [uiState, setUiState] = useState({
75
76
  isMenuOpen: false,
76
77
  showUserChooser: false,
@@ -102,7 +103,7 @@ const RecipientList = ({ recipients, title, tid, qd, onAdd, onRemove, onQDChange
102
103
  onAdd(recipientsToAdd);
103
104
  }
104
105
  setUiState(prevState => ({ ...prevState, showUserChooser: false }));
105
- }, []);
106
+ }, [onAdd]);
106
107
  const handleGroupChosen = useCallback((IDs) => {
107
108
  if (IDs && IDs.length > 0) {
108
109
  const recipientsToAdd = IDs.map(id => ({
@@ -113,7 +114,7 @@ const RecipientList = ({ recipients, title, tid, qd, onAdd, onRemove, onQDChange
113
114
  onAdd(recipientsToAdd);
114
115
  }
115
116
  setUiState(prevState => ({ ...prevState, showGroupChooser: false }));
116
- }, []);
117
+ }, [onAdd]);
117
118
  const handleMetadataChosen = useCallback((IDs) => {
118
119
  if (IDs && IDs.length > 0) {
119
120
  const recipientsToAdd = IDs.map(item => ({
@@ -124,8 +125,11 @@ const RecipientList = ({ recipients, title, tid, qd, onAdd, onRemove, onQDChange
124
125
  onAdd(recipientsToAdd);
125
126
  }
126
127
  setUiState(prevState => ({ ...prevState, showMetadataChooser: false }));
127
- }, []);
128
+ }, [onAdd]);
129
+ const isMaxReached = maxRecipients !== undefined && recipients.length >= maxRecipients;
128
130
  const handleAddClick = () => {
131
+ if (isMaxReached)
132
+ return;
129
133
  setUiState(prevState => ({ ...prevState, isMenuOpen: !prevState.isMenuOpen }));
130
134
  };
131
135
  const handleRecipientClick = useCallback((index) => {
@@ -195,11 +199,11 @@ const RecipientList = ({ recipients, title, tid, qd, onAdd, onRemove, onQDChange
195
199
  document.removeEventListener('keydown', handleKeyPress);
196
200
  };
197
201
  }, [handleKeyPress]);
198
- return (_jsxs(RecipientsColumn, { children: [_jsxs(HeaderContainer, { children: [_jsx("p", { style: { fontWeight: 600 }, children: title }), _jsx(TMButton, { btnStyle: 'icon', caption: SDKUI_Localizator.AddRecipient, icon: _jsx(IconAdd, {}), onClick: handleAddClick }), uiState.isMenuOpen && renderFloatingMenu()] }), _jsx("div", { style: { height: '150px', overflowY: 'auto', gap: '5px', display: 'flex', flexDirection: 'column' }, children: recipients.map((recipient, index) => (_jsxs(RecipientItem, { "$isSelected": uiState.selectedRecipientIndex === index, onClick: () => handleRecipientClick(index), tabIndex: 0, children: [_jsx(IconDelete, { color: '#c00', cursor: 'pointer', onClick: (e) => {
199
- e.stopPropagation();
200
- onRemove(recipient);
201
- setUiState(prevState => ({ ...prevState, selectedRecipientIndex: null })); // Resetta la selezione
202
- } }), renderActorViewer(recipient)] }, index))) }), uiState.showUserChooser && _jsx(TMUserChooserForm, { allowMultipleSelection: true, allowSorting: true, onClose: () => setUiState(prevState => ({ ...prevState, showUserChooser: false })), onChoose: (IDs) => handleUserChosen(IDs) }), uiState.showGroupChooser && _jsx(TMGroupChooserForm, { allowMultipleSelection: true, allowSorting: true, onClose: () => setUiState(prevState => ({ ...prevState, showGroupChooser: false })), onChoose: (IDs) => handleGroupChosen(IDs) }), uiState.showMetadataChooser && tid && _jsx(TMMetadataChooserForm, { allowMultipleSelection: true, allowSorting: true, tids: [tid], onClose: () => setUiState(prevState => ({ ...prevState, showMetadataChooser: false })), onChoose: (IDs) => handleMetadataChosen(IDs) }), uiState.showQdEditor &&
202
+ return (_jsxs(RecipientsColumn, { children: [_jsxs(HeaderContainer, { children: [_jsx("p", { style: { fontWeight: 600 }, children: title }), _jsx(TMButton, { btnStyle: 'icon', caption: SDKUI_Localizator.AddRecipient, icon: _jsx(IconAdd, {}), onClick: handleAddClick, disabled: isMaxReached }), uiState.isMenuOpen && !isMaxReached && renderFloatingMenu()] }), _jsx(TMVilViewer, { vil: validationItems }), _jsx("div", { style: { height: '150px', overflowY: 'auto', gap: '5px', display: 'flex', flexDirection: 'column' }, children: recipients.map((recipient, index) => (_jsxs(RecipientItem, { "$isSelected": uiState.selectedRecipientIndex === index, onClick: () => handleRecipientClick(index), tabIndex: 0, children: [_jsx("span", { style: { display: 'flex', alignItems: 'center', flexShrink: 0 }, children: _jsx(IconDelete, { color: '#c00', cursor: 'pointer', onClick: (e) => {
203
+ e.stopPropagation();
204
+ onRemove(recipient);
205
+ setUiState(prevState => ({ ...prevState, selectedRecipientIndex: null }));
206
+ } }) }), _jsx("span", { style: { flex: 1, minWidth: 0, display: 'flex', alignItems: 'center' }, children: renderActorViewer(recipient) })] }, index))) }), uiState.showUserChooser && _jsx(TMUserChooserForm, { allowMultipleSelection: true, allowSorting: true, onClose: () => setUiState(prevState => ({ ...prevState, showUserChooser: false })), onChoose: (IDs) => handleUserChosen(IDs) }), uiState.showGroupChooser && _jsx(TMGroupChooserForm, { allowMultipleSelection: true, allowSorting: true, onClose: () => setUiState(prevState => ({ ...prevState, showGroupChooser: false })), onChoose: (IDs) => handleGroupChosen(IDs) }), uiState.showMetadataChooser && tid && _jsx(TMMetadataChooserForm, { allowMultipleSelection: true, allowSorting: true, tids: [tid], onClose: () => setUiState(prevState => ({ ...prevState, showMetadataChooser: false })), onChoose: (IDs) => handleMetadataChosen(IDs) }), uiState.showQdEditor &&
203
207
  _jsx(TMModal, { title: SDKUI_Localizator.QueryDefine, onClose: () => setUiState(prevState => ({ ...prevState, showQdEditor: false })), children: _jsx(TMQueryEditor, { inputData: qd, formMode: FormModes.Update, showDistinct: true, onApplied: handleQdChosen, onClose: () => setUiState(prevState => ({ ...prevState, showQdEditor: false })) }) })] }));
204
208
  };
205
209
  export default RecipientList;
@@ -8,13 +8,15 @@ import ConnectionComponent from './ConnectionComponent';
8
8
  import DiagramItemComponent from './DiagramItemComponent';
9
9
  import DiagramItemSvgContent from './DiagramItemSvgContent';
10
10
  import { calculateArrowAngle, downloadFile, getConnectionPoint, getNewWfDiagram, isConnectionNonLinear, validateDiagram } from './workflowHelpers';
11
- import { IconFlowChart, IconUndo, IconRestore, IconAdjust, IconCopy, IconCut, IconPaste, IconPin, IconUnpin, IconChevronRight, IconCloseOutline, IconNew, SDKUI_Localizator, generateUUID, IconExport, IconImport, IconWindowMaximize, IconZoomIn, IconZoomOut, IconPencil, IconLock, LocalizeDiagramItemType, IconWindowMinimize, IconZoomAuto } from '../../../../helper';
11
+ import { IconFlowChart, IconUndo, IconRestore, IconAdjust, IconCopy, IconCut, IconPaste, IconPin, IconUnpin, IconChevronRight, IconCloseOutline, IconNew, SDKUI_Localizator, generateUUID, IconExport, IconImport, IconWindowMaximize, IconZoomIn, IconZoomOut, IconPencil, IconLock, LocalizeDiagramItemType, IconWindowMinimize, IconZoomAuto, IconCloseCircle, IconSuccess } from '../../../../helper';
12
12
  import { ButtonNames, TMExceptionBoxManager, TMMessageBoxManager } from '../../../base/TMPopUp';
13
13
  import { StyledLoadingContainer, StyledSpinner } from '../../../base/Styled';
14
14
  import DiagramItemForm from './DiagramItemForm';
15
15
  import ReactDOM from 'react-dom';
16
16
  import ConnectionForm from './ConnectionForm';
17
17
  import TMFloatingMenuBar from '../../../NewComponents/FloatingMenuBar';
18
+ import TMContextMenu from '../../../NewComponents/ContextMenu/TMContextMenu';
19
+ import { TMColors } from '../../../../utils/theme';
18
20
  const ZoomLevelText = styled.span `
19
21
  font-size: 0.9em;
20
22
  color: #555;
@@ -331,6 +333,9 @@ const WFDiagram = ({ xmlDiagramString, currentSetID, allowEdit = true, onDiagram
331
333
  const [wfDiagram, setWfDiagram] = useState(null);
332
334
  const [selectedItems, setSelectedItems] = useState(new Set());
333
335
  const [selectedConnections, setSelectedConnections] = useState(new Set());
336
+ // Context menu per le connections
337
+ const [connectionContextMenuPosition, setConnectionContextMenuPosition] = useState({ x: 0, y: 0 });
338
+ const [contextMenuConnectionId, setContextMenuConnectionId] = useState(null);
334
339
  const [wfDiagramHistory, setWfDiagramHistory] = useState([]);
335
340
  const [historyIndex, setHistoryIndex] = useState(-1);
336
341
  const isUndoingRedoing = useRef(false);
@@ -1311,6 +1316,77 @@ const WFDiagram = ({ xmlDiagramString, currentSetID, allowEdit = true, onDiagram
1311
1316
  if (!isCtrlPressed)
1312
1317
  setSelectedItems(new Set());
1313
1318
  }, [isReadOnly]);
1319
+ const handleConnectionContextMenu = useCallback((id, event) => {
1320
+ if (isReadOnly)
1321
+ return;
1322
+ event.preventDefault();
1323
+ event.stopPropagation();
1324
+ // Trova la connection
1325
+ const connection = wfDiagram?.Connections.find(conn => conn.ID === id);
1326
+ if (!connection)
1327
+ return;
1328
+ // Verifica se esce da un DiagramItemTypes.Condition o Approval
1329
+ const sourceItem = wfDiagram?.DiagramItems.find(item => item.ID === connection.Source.ParentDiagramItem.ID);
1330
+ if (!sourceItem || ![DiagramItemTypes.Condition, DiagramItemTypes.Approval].includes(sourceItem.Type))
1331
+ return;
1332
+ // Mostra il context menu
1333
+ setContextMenuConnectionId(id);
1334
+ setConnectionContextMenuPosition({ x: event.clientX, y: event.clientY });
1335
+ }, [isReadOnly, wfDiagram]);
1336
+ const handleChangeConnectionOutputStatus = useCallback((connectionId) => {
1337
+ if (isReadOnly || !wfDiagram)
1338
+ return;
1339
+ const connection = wfDiagram.Connections.find(conn => conn.ID === connectionId);
1340
+ if (!connection)
1341
+ return;
1342
+ // Cambia l'OutputStatus da Completed a Rejected e viceversa
1343
+ const newStatus = connection.OutputStatus === WorkItemStatus.Completed
1344
+ ? WorkItemStatus.Rejected
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);
1355
+ const updatedDiagram = {
1356
+ ...wfDiagram,
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
+ })
1364
+ };
1365
+ updateDiagram(updatedDiagram);
1366
+ setWfDiagram(updatedDiagram);
1367
+ setContextMenuConnectionId(null);
1368
+ }, [isReadOnly, wfDiagram, updateDiagram]);
1369
+ const closeConnectionContextMenu = useCallback(() => {
1370
+ setContextMenuConnectionId(null);
1371
+ }, []);
1372
+ // Menu items per il context menu delle connections
1373
+ const connectionContextMenuItems = useMemo(() => {
1374
+ if (!contextMenuConnectionId || !wfDiagram)
1375
+ return [];
1376
+ const connection = wfDiagram.Connections.find(conn => conn.ID === contextMenuConnectionId);
1377
+ if (!connection)
1378
+ return [];
1379
+ const targetStatus = connection.OutputStatus === WorkItemStatus.Completed
1380
+ ? SDKUI_Localizator.WorkItemStatus_Rejected
1381
+ : SDKUI_Localizator.WorkItemStatus_Completed;
1382
+ return [{
1383
+ icon: connection.OutputStatus === WorkItemStatus.Completed
1384
+ ? _jsx(IconCloseCircle, { color: TMColors.error, fontSize: 16 })
1385
+ : _jsx(IconSuccess, { color: TMColors.success, fontSize: 16 }),
1386
+ name: SDKUI_Localizator.ChangeStatusTo.replaceParams(targetStatus),
1387
+ onClick: () => handleChangeConnectionOutputStatus(contextMenuConnectionId)
1388
+ }];
1389
+ }, [contextMenuConnectionId, wfDiagram, handleChangeConnectionOutputStatus]);
1314
1390
  const handleDrag = useCallback((id, newX, newY) => {
1315
1391
  if (isReadOnly)
1316
1392
  return;
@@ -1393,10 +1469,15 @@ const WFDiagram = ({ xmlDiagramString, currentSetID, allowEdit = true, onDiagram
1393
1469
  if (sourceItem.Type === DiagramItemTypes.Condition || sourceItem.Type === DiagramItemTypes.Approval) {
1394
1470
  const existingConnectionsFromSource = wfDiagram.Connections.filter(conn => conn.Source.ParentDiagramItem.ID === sourceItem.ID);
1395
1471
  if (existingConnectionsFromSource.length === 0) {
1472
+ // Prima connessione → Completed
1396
1473
  outputStatus = WorkItemStatus.Completed;
1397
1474
  }
1398
1475
  else if (existingConnectionsFromSource.length === 1) {
1399
- outputStatus = WorkItemStatus.Rejected;
1476
+ // Seconda connessione → contrario della prima
1477
+ const firstConnection = existingConnectionsFromSource[0];
1478
+ outputStatus = firstConnection.OutputStatus === WorkItemStatus.Completed
1479
+ ? WorkItemStatus.Rejected
1480
+ : WorkItemStatus.Completed;
1400
1481
  }
1401
1482
  }
1402
1483
  const newConnection = {
@@ -1562,6 +1643,18 @@ const WFDiagram = ({ xmlDiagramString, currentSetID, allowEdit = true, onDiagram
1562
1643
  const newDiagram = { ...wfDiagram, DiagramItems: updatedDiagramItems };
1563
1644
  updateDiagram(newDiagram);
1564
1645
  }, [wfDiagram, updateDiagram]);
1646
+ const handleStatusItemEdited = useCallback((originalItem, editedItem) => {
1647
+ if (!wfDiagram)
1648
+ return;
1649
+ const updatedDiagramItems = wfDiagram.DiagramItems.map(item => {
1650
+ if (item.Type === DiagramItemTypes.Status && item.StatusValue === originalItem.value) {
1651
+ return { ...item, ItemName: editedItem.name || '', StatusValue: editedItem.value };
1652
+ }
1653
+ return item;
1654
+ });
1655
+ const newDiagram = { ...wfDiagram, DiagramItems: updatedDiagramItems };
1656
+ updateDiagram(newDiagram);
1657
+ }, [wfDiagram, updateDiagram]);
1565
1658
  const handleUpdateConnection = useCallback((updatedConnection) => {
1566
1659
  setWfDiagram(prevDiagram => {
1567
1660
  if (!prevDiagram)
@@ -1820,7 +1913,7 @@ const WFDiagram = ({ xmlDiagramString, currentSetID, allowEdit = true, onDiagram
1820
1913
  fullScreenRef.current.focus();
1821
1914
  }
1822
1915
  }, [isFullScreen]);
1823
- const diagramContent = (_jsxs(CanvasContainer, { onDoubleClick: handleCanvasDoubleClick, children: [_jsx("input", { ref: fileInputRef, type: "file", accept: ".xml" // Filtra per file XML
1916
+ const diagramContent = (_jsxs(CanvasContainer, { onDoubleClick: handleCanvasDoubleClick, onContextMenu: (e) => e.preventDefault(), children: [_jsx("input", { ref: fileInputRef, type: "file", accept: ".xml" // Filtra per file XML
1824
1917
  , onChange: handleFileChange, style: { display: 'none' } }), SDK_Globals.tmSession?.SessionDescr?.appModuleID === AppModules.SURFER ?
1825
1918
  _jsx(TMFloatingMenuBar, { containerRef: diagramRef, defaultPosition: { x: 45, y: 85 }, enableConfigMode: false, fixedItems: [
1826
1919
  { icon: _jsx(IconZoomIn, {}), name: SDKUI_Localizator.ZoomIn, disabled: isAutoZoomEnabled, onClick: () => { handleZoomIn(); }, id: 'zoom-in', isPinned: true },
@@ -1842,8 +1935,12 @@ const WFDiagram = ({ xmlDiagramString, currentSetID, allowEdit = true, onDiagram
1842
1935
  const sinkPoint = getConnectionPoint(sinkItem, connection.Sink.ConnectorName);
1843
1936
  // Determina se questa è la connessione che stiamo trascinando
1844
1937
  const isThisConnectionBeingDragged = isDraggingExistingConnectionEndpoint && draggingConnectionId === connection.ID;
1845
- return (_jsx(ConnectionComponent, { connection: connection, isSelected: selectedConnections.has(connection.ID), sourcePoint: sourcePoint, sinkPoint: sinkPoint, isTemporary: isThisConnectionBeingDragged, onClick: handleConnectionClick, onDoubleClick: handleDoubleClickConnection, onConnectionEndpointMouseDown: handleConnectionEndpointMouseDown }, connection.ID));
1846
- }), isDrawingConnection && tempConnectionPathData && (_jsx(TempConnectionPath, { d: tempConnectionPathData })), isDraggingExistingConnectionEndpoint && tempConnectionPathData && (_jsx(TempConnectionPath, { d: tempConnectionPathData })), isDrawingSelectionRect && currentSelectionRect && (_jsx(SelectionRect, { x: currentSelectionRect.x, y: currentSelectionRect.y, width: currentSelectionRect.width, height: currentSelectionRect.height }))] }) })) : (_jsx(DiagramMessage, { children: `${SDKUI_Localizator.WorkflowDiagramMissingOrInvalid} ...` })) }), isModalOpen && itemToEdit && (_jsx(DiagramItemForm, { itemToEdit: itemToEdit, wf: wfDiagram?.Info, onClose: handleCloseModal, onApply: handleUpdateDiagramItem })), isConnectionModalOpen && connectionToEdit && (_jsx(ConnectionForm, { connectionToEdit: connectionToEdit, onClose: () => setIsConnectionModalOpen(false), onApply: handleUpdateConnection }))] }));
1938
+ return (_jsx(ConnectionComponent, { connection: connection, isSelected: selectedConnections.has(connection.ID), sourcePoint: sourcePoint, sinkPoint: sinkPoint, isTemporary: isThisConnectionBeingDragged, onClick: handleConnectionClick, onDoubleClick: handleDoubleClickConnection, onConnectionEndpointMouseDown: handleConnectionEndpointMouseDown, onContextMenu: handleConnectionContextMenu }, connection.ID));
1939
+ }), isDrawingConnection && tempConnectionPathData && (_jsx(TempConnectionPath, { d: tempConnectionPathData })), isDraggingExistingConnectionEndpoint && tempConnectionPathData && (_jsx(TempConnectionPath, { d: tempConnectionPathData })), isDrawingSelectionRect && currentSelectionRect && (_jsx(SelectionRect, { x: currentSelectionRect.x, y: currentSelectionRect.y, width: currentSelectionRect.width, height: currentSelectionRect.height }))] }) })) : (_jsx(DiagramMessage, { children: `${SDKUI_Localizator.WorkflowDiagramMissingOrInvalid} ...` })) }), isModalOpen && itemToEdit && (_jsx(DiagramItemForm, { itemToEdit: itemToEdit, wf: wfDiagram?.Info, onClose: handleCloseModal, onApply: handleUpdateDiagramItem, onStatusItemEdited: handleStatusItemEdited })), isConnectionModalOpen && connectionToEdit && (_jsx(ConnectionForm, { connectionToEdit: connectionToEdit, onClose: () => setIsConnectionModalOpen(false), onApply: handleUpdateConnection })), _jsx(TMContextMenu, { items: connectionContextMenuItems, externalControl: {
1940
+ visible: contextMenuConnectionId !== null,
1941
+ position: connectionContextMenuPosition,
1942
+ onClose: closeConnectionContextMenu
1943
+ } })] }));
1847
1944
  return (_jsxs(_Fragment, { children: [!isFullScreen && (_jsx(DiagramWrapper, { ref: diagramRef, children: diagramContent })), isFullScreen && ReactDOM.createPortal(_jsx(FullScreenContainer, { ref: fullScreenRef, tabIndex: 0, onKeyDown: handleFullScreenKeyDown, children: diagramContent }), document.body)] }));
1848
1945
  };
1849
1946
  export default WFDiagram;
@@ -1,6 +1,7 @@
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
+ import { tosToActors } from './WorkitemRecipientsEditor';
4
5
  /**
5
6
  * Calculates the angle in degrees of an arrow based on two points.
6
7
  * @param prevPoint The previous point on the trajectory.
@@ -318,72 +319,73 @@ export const workflowValidator = async (wf) => {
318
319
  const vil = await wfDiagramItemValidator(item);
319
320
  vil.forEach(v => v.PropertyScopes = ['diagramItem']);
320
321
  validationItems.push(...vil);
322
+ const itemType = LocalizeDiagramItemType(item.Type);
321
323
  switch (item.Type) {
322
324
  case DiagramItemTypes.Start:
323
325
  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']));
326
+ validationItems.push(new ValidationItem(ResultTypes.ERROR, itemType, SDKUI_Localizator.WorkflowDiagramStartMustHaveOutgoing, ['diagramItem']));
325
327
  }
326
328
  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']));
329
+ validationItems.push(new ValidationItem(ResultTypes.ERROR, itemType, SDKUI_Localizator.WorkflowDiagramStartCannotHaveIncoming, ['diagramItem']));
328
330
  }
329
331
  break;
330
332
  case DiagramItemTypes.End:
331
333
  case DiagramItemTypes.Exit:
332
334
  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']));
335
+ validationItems.push(new ValidationItem(ResultTypes.ERROR, itemType, SDKUI_Localizator.WorkflowDiagramElementMustHaveIncoming.replaceParams(itemType), ['diagramItem']));
334
336
  }
335
337
  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']));
338
+ validationItems.push(new ValidationItem(ResultTypes.ERROR, itemType, SDKUI_Localizator.WorkflowDiagramElementCannotHaveOutgoing.replaceParams(itemType), ['diagramItem']));
337
339
  }
338
340
  break;
339
341
  case DiagramItemTypes.Condition:
340
342
  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']));
343
+ validationItems.push(new ValidationItem(ResultTypes.WARNING, itemType, SDKUI_Localizator.WorkflowDiagramConditionTwoOutgoing.replaceParams(item.ItemName), ['diagramItem']));
342
344
  }
343
345
  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']));
346
+ validationItems.push(new ValidationItem(ResultTypes.ERROR, itemType, SDKUI_Localizator.WorkflowDiagramConditionMustHaveIncoming.replaceParams(item.ItemName), ['diagramItem']));
345
347
  }
346
348
  break;
347
349
  case DiagramItemTypes.Approval:
348
350
  case DiagramItemTypes.ExecTask:
349
351
  case DiagramItemTypes.DataEntry:
350
352
  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']));
353
+ validationItems.push(new ValidationItem(ResultTypes.WARNING, itemType, SDKUI_Localizator.WorkflowDiagramElementShouldHaveTwoOutgoing.replaceParams(item.ItemName), ['diagramItem']));
352
354
  }
353
355
  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']));
356
+ validationItems.push(new ValidationItem(ResultTypes.WARNING, itemType, SDKUI_Localizator.WorkflowDiagramElementShouldHaveIncoming.replaceParams(item.ItemName), ['diagramItem']));
355
357
  }
356
358
  break;
357
359
  case DiagramItemTypes.Notification:
358
360
  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']));
361
+ validationItems.push(new ValidationItem(ResultTypes.WARNING, itemType, SDKUI_Localizator.WorkflowDiagramElementShouldHaveOutgoing.replaceParams(item.ItemName), ['diagramItem']));
360
362
  }
361
363
  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']));
364
+ validationItems.push(new ValidationItem(ResultTypes.WARNING, itemType, SDKUI_Localizator.WorkflowDiagramElementShouldHaveIncoming.replaceParams(item.ItemName), ['diagramItem']));
363
365
  }
364
366
  break;
365
367
  case DiagramItemTypes.UpdateDcmt:
366
368
  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']));
369
+ validationItems.push(new ValidationItem(ResultTypes.WARNING, itemType, SDKUI_Localizator.WorkflowDiagramElementShouldHaveOneOutgoing.replaceParams(item.ItemName), ['diagramItem']));
368
370
  }
369
371
  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']));
372
+ validationItems.push(new ValidationItem(ResultTypes.WARNING, itemType, SDKUI_Localizator.WorkflowDiagramElementShouldHaveIncoming.replaceParams(item.ItemName), ['diagramItem']));
371
373
  }
372
374
  break;
373
375
  case DiagramItemTypes.Status:
374
376
  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']));
377
+ validationItems.push(new ValidationItem(ResultTypes.WARNING, itemType, SDKUI_Localizator.WorkflowDiagramElementShouldHaveOneOutgoing.replaceParams(item.ItemName), ['diagramItem']));
376
378
  }
377
379
  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']));
380
+ validationItems.push(new ValidationItem(ResultTypes.WARNING, itemType, SDKUI_Localizator.WorkflowDiagramElementShouldHaveIncoming.replaceParams(item.ItemName), ['diagramItem']));
379
381
  }
380
382
  break;
381
383
  case DiagramItemTypes.RunApp:
382
384
  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']));
385
+ validationItems.push(new ValidationItem(ResultTypes.WARNING, itemType, SDKUI_Localizator.WorkflowDiagramElementShouldHaveOutgoing.replaceParams(item.ItemName), ['diagramItem']));
384
386
  }
385
387
  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']));
388
+ validationItems.push(new ValidationItem(ResultTypes.WARNING, itemType, SDKUI_Localizator.WorkflowDiagramElementShouldHaveIncoming.replaceParams(item.ItemName), ['diagramItem']));
387
389
  }
388
390
  break;
389
391
  }
@@ -480,7 +482,17 @@ export const wfDiagramItemValidator = async (d) => {
480
482
  qvo.DoOrderByValidation = false;
481
483
  await PlatformObjectValidator.QueryValidatorAsync(d.QD, vil, qvo);
482
484
  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]));
485
+ vil.push(new ValidationItem(ResultTypes.ERROR, LocalizeDiagramItemType(d.Type), `La query della condizione '${d.ItemName}' non contiene criteri di selezione`, [DiagramItemProps.QD]));
486
+ }
487
+ break;
488
+ case DiagramItemTypes.CaseFlow_Create:
489
+ PlatformObjectValidator.RequiredStringValidator(d.ItemName, DiagramItemProps.ItemName, vil, SDKUI_Localizator.Name);
490
+ PlatformObjectValidator.RequiredStringValidator(d.Tos2, DiagramItemProps.Tos2, vil, SDKUI_Localizator.OwnerName);
491
+ if (d.Tos2) {
492
+ const { andRecipients } = tosToActors(d.Tos2);
493
+ if (andRecipients.length > 1) {
494
+ vil.push(new ValidationItem(ResultTypes.ERROR, DiagramItemProps.Tos2, SDKUI_Localizator.WorkflowOnlyOneOwnerAllowed));
495
+ }
484
496
  }
485
497
  break;
486
498
  }
@@ -115,7 +115,7 @@ const TMLoginForm = (props) => {
115
115
  const [dcmtArchive, setDcmtArchive] = useState();
116
116
  const [manualArchiveID, setManualArchiveID] = useState('');
117
117
  const [authMode, setAuthMode] = useState(AuthenticationModes.TopMedia);
118
- const [username, setUsername] = useState('SysAdmin');
118
+ const [username, setUsername] = useState('');
119
119
  const [password, setPassword] = useState('');
120
120
  const [authDomain, setAuthDomain] = useState('');
121
121
  const [usernameOnBehalf, setUsernameOnBehalf] = useState('');
@@ -11,7 +11,7 @@ import { TMColors } from '../../utils/theme';
11
11
  import TMValidationItemsList from '../grids/TMValidationItemsList';
12
12
  import TMModal from '../base/TMModal';
13
13
  import { DeviceType, useDeviceType } from '../base/TMDeviceProvider';
14
- const TMSaveForm = ({ id, formMode = FormModes.Update, showToolbar = true, skipIsModifiedCheck = false, title, children, isModal, exception, customToolbarElements, hasNavigation, showSaveButton = true, customSaveButton, customTooltipSaveButton, showBackButton, showWarningsCount = true, showErrorCount = true, showUndoButton = true, onClose, onSaveAsync, onNext, onPrev, canNext, canPrev, isModified, onShowList, validationItems = [], onUndo, onCancel, width, height, askClosingConfirm = false, showTitleFormMode = true, showCloseButton = true }) => {
14
+ const TMSaveForm = ({ id, formMode = FormModes.Update, showToolbar = true, skipIsModifiedCheck = false, title, children, isModal, exception, customToolbarElements, hasNavigation, showSaveButton = true, customSaveButton, customTooltipSaveButton, showBackButton, showWarningsCount = true, showErrorCount = true, showUndoButton = true, onClose, onSaveAsync, onNext, onPrev, canNext, canPrev, isModified, onShowList, validationItems = [], onUndo, onCancel, width, height, askClosingConfirm = false, showTitleFormMode = true, showCloseButton = true, resizable = true }) => {
15
15
  const [showList, setShowList] = useState(true);
16
16
  const [showErrorGrid, setShowErrorGrid] = useState(false);
17
17
  const deviceType = useDeviceType();
@@ -65,26 +65,74 @@ const TMSaveForm = ({ id, formMode = FormModes.Update, showToolbar = true, skipI
65
65
  }
66
66
  });
67
67
  };
68
- const doClose = () => {
68
+ const doClose = async () => {
69
+ // Se non ci sono modifiche o vogliamo ignorare il controllo delle modifiche
69
70
  if (!isModified || skipIsModifiedCheck) {
70
71
  onClose?.();
71
- deviceType === DeviceType.MOBILE && setShowList(true), onShowList?.(true);
72
+ // Se il dispositivo è mobile, mostra di nuovo la lista
73
+ if (deviceType === DeviceType.MOBILE) {
74
+ setShowList(true);
75
+ onShowList?.(true);
76
+ }
72
77
  return;
73
78
  }
79
+ // Determina il messaggio e i pulsanti da mostrare in base alla presenza di errori
80
+ const hasValidationErrors = validationItems.length > 0;
81
+ const message = (isModified && hasValidationErrors) ? SDKUI_Localizator.FormErrorsProceedQuestion : SDKUI_Localizator.SaveQuestion;
82
+ const buttons = hasValidationErrors
83
+ ? [ButtonNames.YES, ButtonNames.NO]
84
+ : [ButtonNames.YES, ButtonNames.NO, ButtonNames.CANCEL];
85
+ // Mostra il messaggio di conferma
74
86
  TMMessageBoxManager.show({
75
- parentId: isModal ? "TMSaveFormShowConfirmForClose-" + id : undefined,
76
- message: SDKUI_Localizator.SaveQuestion, buttons: [ButtonNames.YES, ButtonNames.NO, ButtonNames.CANCEL],
77
- onButtonClick: async (e) => {
87
+ parentId: isModal ? `TMSaveFormShowConfirmForClose-${id}` : undefined,
88
+ message,
89
+ buttons,
90
+ onButtonClick: async (buttonClicked) => {
78
91
  try {
79
- if (e == ButtonNames.CANCEL)
80
- return;
81
- if (e == ButtonNames.NO)
82
- deviceType === DeviceType.MOBILE && (onUndo(), setShowList(true), onShowList?.(true));
83
- if (e == ButtonNames.YES)
84
- deviceType === DeviceType.MOBILE ? (await onSaveAsync?.(), setShowList(true), onShowList?.(true)) : await onSaveAsync?.();
92
+ // Caso con errori di validazione
93
+ if (hasValidationErrors) {
94
+ if (buttonClicked === ButtonNames.NO)
95
+ return; // Non fare nulla
96
+ if (buttonClicked === ButtonNames.YES) {
97
+ if (deviceType === DeviceType.MOBILE) {
98
+ onUndo();
99
+ setShowList(true);
100
+ onShowList?.(true);
101
+ }
102
+ else {
103
+ onUndo();
104
+ }
105
+ }
106
+ }
107
+ else {
108
+ // Caso senza errori
109
+ switch (buttonClicked) {
110
+ case ButtonNames.CANCEL:
111
+ return; // Non fare nulla
112
+ case ButtonNames.NO:
113
+ if (deviceType === DeviceType.MOBILE) {
114
+ onUndo();
115
+ setShowList(true);
116
+ onShowList?.(true);
117
+ }
118
+ break;
119
+ case ButtonNames.YES:
120
+ if (deviceType === DeviceType.MOBILE) {
121
+ await onSaveAsync?.();
122
+ setShowList(true);
123
+ onShowList?.(true);
124
+ }
125
+ else {
126
+ await onSaveAsync?.();
127
+ }
128
+ break;
129
+ }
130
+ }
131
+ // Chiude il form/modal
85
132
  onClose?.();
86
133
  }
87
134
  catch (ex) {
135
+ // Mostra eventuali eccezioni
88
136
  TMExceptionBoxManager.show({ exception: ex });
89
137
  }
90
138
  }
@@ -102,7 +150,7 @@ const TMSaveForm = ({ id, formMode = FormModes.Update, showToolbar = true, skipI
102
150
  _jsx("div", { style: { width: '100%', height: '100%', marginTop: '50px', display: 'flex', alignItems: 'center', justifyContent: 'center', flexDirection: 'column', color: getColor('error') }, children: 'Si è verificato un errore' })
103
151
  : _jsx(_Fragment, { children: children }) }), showErrorGrid && validationItems.length > 0 ? _jsx(TMCard, { scrollY: true, padding: false, showBorder: false, children: _jsx(TMValidationItemsList, { validationItems: validationItems }) }) : _jsx(_Fragment, {})] }) }), (isModal && onClose) && _jsx("div", { id: "TMSaveFormShowConfirmForClose-" + id })] }));
104
152
  };
105
- return (_jsx(_Fragment, { children: (isModal && onClose) ? _jsx(_Fragment, { children: _jsx(TMModal, { title: `${title}${showTitleFormMode ? ` - ${LocalizeFormModes(formMode)}` : ''}`, onClose: doClose, width: width ?? '100%', height: height ?? '100%', hidePopup: false, askClosingConfirm: askClosingConfirm, showCloseButton: showCloseButton, children: _jsx("div", { style: { width: "100%", height: "100%", display: 'block' }, children: renderSaveForm() }) }) })
153
+ return (_jsx(_Fragment, { children: (isModal && onClose) ? _jsx(_Fragment, { children: _jsx(TMModal, { title: `${title}${showTitleFormMode ? ` - ${LocalizeFormModes(formMode)}` : ''}`, onClose: doClose, width: width ?? '100%', height: height ?? '100%', hidePopup: false, askClosingConfirm: askClosingConfirm, showCloseButton: showCloseButton, resizable: resizable, children: _jsx("div", { style: { width: "100%", height: "100%", display: 'block' }, children: renderSaveForm() }) }) })
106
154
  : renderSaveForm() }));
107
155
  };
108
156
  export default TMSaveForm;