@topconsultnpm/sdkui-react 6.20.0-dev1.44 → 6.20.0-dev1.45

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.
@@ -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, TemplateTIDs, WorkItemMetadataNames } from '@topconsultnpm/sdk-ts';
5
- import { IconUndo, IconPencil, IconFunction, IconMenuVertical, IconDataList, SDKUI_Localizator, IconNull, stringIsNullOrEmpty, deepCompare, SDKUI_Globals, IconDcmtTypeSys } from "../../helper";
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";
6
6
  import { TMColors } from "../../utils/theme";
7
7
  import TMButton from "../base/TMButton";
8
8
  import TMDropDownMenu from "../base/TMDropDownMenu";
@@ -568,7 +568,7 @@ const TMMetadataValues = ({ showCheckBoxes = ShowCheckBoxesMode.Never, checkPerm
568
568
  if (allSystem) {
569
569
  return metadataValues.map((item) => renderMetadataItem(item, true));
570
570
  }
571
- if (currentDTD?.templateTID === TemplateTIDs.WF_WIApprView && !isReadOnly) {
571
+ if (isApprovalWorkflowView(currentDTD) && !isReadOnly) {
572
572
  return layoutWorkItem;
573
573
  }
574
574
  switch (currentDTD?.id) {
@@ -1,14 +1,14 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
3
3
  import TMDcmtPreview from './TMDcmtPreview';
4
- import { AccessLevels, ArchiveConstraints, ArchiveEngineByID, DcmtTypeListCacheService, LayoutCacheService, LayoutModes, MetadataDataTypes, ObjectClasses, ResultTypes, SDK_Globals, SDK_Localizator, SystemMIDsAsNumber, SystemTIDs, Task_States, TemplateTIDs, TID_DID, UpdateEngineByID, UserListCacheService, ValidationItem, WorkflowCacheService, WorkItemMetadataNames } from '@topconsultnpm/sdk-ts';
4
+ import { AccessLevels, 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';
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';
8
8
  import { useDcmtOperations } from '../../../hooks/useDcmtOperations';
9
9
  import { useRelatedDocuments } from '../../../hooks/useRelatedDocuments';
10
10
  import { getWorkItemSetIDAsync, handleArchiveVisibility, searchResultToMetadataValues } from '../../../helper/queryHelper';
11
- import { genUniqueId, IconShow, SDKUI_Localizator, updateMruTids, IconBoard, IconDcmtTypeSys, IconDetailDcmts, IconDownload, calcIsModified, IconMenuVertical, Globalization, getListMaxItems, getSystemMetadata, IconBoxArchiveIn, IconClear, IconUndo, SDKUI_Globals, IconPreview, isTaskMoreInfo, IconWorkflow, IconSearch, deepCompare, IconCheck, IconActivity, TMImageLibrary, IconStar, IconRelation, IconInfo, IconArchiveDoc, IconDelete, IconPair, IconUnpair, IconArchiveMaster, IconArchiveDetail, getDcmtCicoStatus, IconFileDots, IconCustom } from '../../../helper';
11
+ import { genUniqueId, IconShow, SDKUI_Localizator, updateMruTids, IconBoard, IconDcmtTypeSys, IconDetailDcmts, IconDownload, calcIsModified, IconMenuVertical, Globalization, getListMaxItems, getSystemMetadata, IconBoxArchiveIn, IconClear, IconUndo, SDKUI_Globals, IconPreview, isTaskMoreInfo, IconWorkflow, IconSearch, deepCompare, IconCheck, IconActivity, TMImageLibrary, IconStar, IconRelation, IconInfo, IconArchiveDoc, IconDelete, IconPair, IconUnpair, IconArchiveMaster, IconArchiveDetail, getExceptionMessage, isApprovalWorkflowView, getDcmtCicoStatus, IconFileDots, IconCustom } from '../../../helper';
12
12
  import { hasDetailRelations, hasMasterRelations, isXMLFileExt } from '../../../helper/dcmtsHelper';
13
13
  import { Gutters, TMColors } from '../../../utils/theme';
14
14
  import { StyledFormButtonsContainer, StyledLoadingContainer, StyledModalContainer, StyledReferenceButton, StyledSpinner, StyledToolbarCardContainer } from '../../base/Styled';
@@ -119,6 +119,7 @@ const TMDcmtForm = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTa
119
119
  const [dcmtReferences, setDcmtReferences] = useState(undefined);
120
120
  // Stato per triggerare il refresh del blog dall'esterno
121
121
  const [refreshBlogTrigger, setRefreshBlogTrigger] = useState(0);
122
+ const [wfError, setWfError] = useState(null);
122
123
  const triggerBlogRefresh = useCallback(async () => {
123
124
  setRefreshBlogTrigger(prev => prev + 1);
124
125
  }, []);
@@ -135,7 +136,7 @@ const TMDcmtForm = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTa
135
136
  }, [allowButtonsRefs]);
136
137
  const { openConfirmAttachmentsDialog, ConfirmAttachmentsDialog } = useInputAttachmentsDialog();
137
138
  const { abortController, showWaitPanel, waitPanelTitle, showPrimary, waitPanelTextPrimary, waitPanelValuePrimary, waitPanelMaxValuePrimary, showSecondary, waitPanelTextSecondary, waitPanelValueSecondary, waitPanelMaxValueSecondary, downloadDcmtsAsync, runOperationAsync } = useDcmtOperations();
138
- const { workflowApproveData } = useWorkflowApprove();
139
+ const { workflowApproveData, getWorkItemsByDID } = useWorkflowApprove();
139
140
  const currentSearchResults = useMemo(() => {
140
141
  if (!formData || formData.length === 0 || !TID || !DID)
141
142
  return [];
@@ -453,74 +454,110 @@ const TMDcmtForm = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTa
453
454
  return;
454
455
  copyCheckoutPathToClipboardCallback({ TID: currentDcmt.tid, DID: currentDcmt.did, FILEEXT: currentDcmt.fileExt }, fromDTD?.name ?? SDKUI_Localizator.SearchResult);
455
456
  };
457
+ // useEffect per il caricamento dei dati del workflow
456
458
  useEffect(() => {
459
+ // Funzione helper per caricare le informazioni del workflow
460
+ const loadWorkflowInfo = async (tid) => {
461
+ await WorkflowCacheService.GetWFInfoAsync(tid)
462
+ .then((result) => {
463
+ if (result) {
464
+ setWorkflows([result]);
465
+ setWfError(null);
466
+ }
467
+ else {
468
+ setWorkflows([]);
469
+ setWfError("Workflow info not found");
470
+ }
471
+ })
472
+ .catch(error => {
473
+ setWorkflows([]);
474
+ console.log("Error fetching workflow info:", error);
475
+ setWfError(getExceptionMessage(error));
476
+ });
477
+ };
457
478
  const loadAllWfData = async () => {
458
- if (layoutMode !== LayoutModes.Update || !DID || fromDTD?.templateTID !== TemplateTIDs.WF_WIApprView) {
479
+ // FASE 1: Validazione prerequisiti
480
+ if (layoutMode !== LayoutModes.Update || !DID) {
459
481
  setWorkItems([]);
460
482
  setWorkflows([]);
461
483
  return;
462
484
  }
463
485
  setIsWFDataLoading(true);
464
486
  try {
465
- // 1. item da processare in modo sincrono
466
- const itemsToProcess = [];
467
- for (const workflow of workflowApproveData) {
468
- for (const dataRow of workflow.dtdResult?.rows ?? []) {
469
- const did = Number(dataRow?.[1]);
470
- if (did === Number(DID)) {
471
- const tid = Number(dataRow?.[0]);
472
- itemsToProcess.push({ tid, did });
473
- }
474
- }
475
- }
487
+ // FASE 2: Raccolta work items: array di tutti i possibili work items che matchano il DID corrente
488
+ const itemsToProcess = getWorkItemsByDID(Number(DID));
489
+ // Se non ci sono work items per questo DID, resetta e esci
476
490
  if (itemsToProcess.length === 0) {
477
491
  setWorkItems([]);
478
492
  setWorkflows([]);
479
493
  setIsWFDataLoading(false);
480
494
  return;
481
495
  }
482
- // promises per i setID in modo condizionale
483
- let setIDPromises;
484
- if (workItemSetIDValue !== undefined) {
485
- // Se abbiamo il setID dal form, non facciamo chiamate di rete.
486
- setIDPromises = itemsToProcess.map(() => Promise.resolve(workItemSetIDValue));
496
+ // FASE 3: Ricerca work item specifico
497
+ // Cerca prima un match esatto con TID e DID correnti
498
+ const foundItem = itemsToProcess.find(item => item.tid === Number(TID) && item.did === Number(DID));
499
+ if (foundItem) {
500
+ // SCENARIO A: Match esatto trovato (TID e DID corrispondono)
501
+ // Il documento corrente è esattamente il work item nel workflow
502
+ let setID = undefined;
503
+ // Prova a usare il setID già presente nei metadati (più veloce)
504
+ if (workItemSetIDValue !== undefined) {
505
+ setID = workItemSetIDValue;
506
+ }
507
+ else {
508
+ // Altrimenti caricalo dal server
509
+ setID = await getWorkItemSetIDAsync(foundItem.tid, foundItem.did);
510
+ }
511
+ // Imposta un singolo work item con il setID caricato
512
+ setWorkItems([{ ...foundItem, setID }]);
513
+ // Carica le informazioni complete del workflow
514
+ await loadWorkflowInfo(foundItem.tid);
487
515
  }
488
516
  else {
489
- // Altrimenti, procediamo con le chiamate di rete come prima.
490
- setIDPromises = itemsToProcess.map(item => getWorkItemSetIDAsync(item.tid, item.did));
517
+ // SCENARIO B: Nessun match esatto, cerca solo per DID
518
+ const itemsByDID = itemsToProcess.filter(item => item.did === Number(DID));
519
+ if (itemsByDID.length === 1) {
520
+ // SCENARIO B.1: Un solo item trovato per DID
521
+ // Situazione sicura: sappiamo esattamente quale work item usare
522
+ const singleItem = itemsByDID[0];
523
+ let setID;
524
+ // Carica il setID (da cache o da server)
525
+ if (workItemSetIDValue !== undefined) {
526
+ setID = workItemSetIDValue;
527
+ }
528
+ else {
529
+ setID = await getWorkItemSetIDAsync(singleItem.tid, singleItem.did);
530
+ }
531
+ setWorkItems([{ ...singleItem, setID }]);
532
+ // Carica le informazioni del workflow
533
+ await loadWorkflowInfo(singleItem.tid);
534
+ }
535
+ else if (itemsByDID.length > 1) {
536
+ // SCENARIO B.2: Più item trovati per lo stesso DID
537
+ // Ambiguità: lo stesso documento appare in più workflow diversi
538
+ const finalWorkItems = itemsByDID.map((item, index) => ({ ...item, setID: undefined }));
539
+ setWorkItems(finalWorkItems);
540
+ setWorkflows([]); // Non carichiamo il workflow in caso di ambiguità
541
+ }
491
542
  }
492
- // Crea un array di Promise per tutte le chiamate a GetWFInfoAsync
493
- const workflowInfoPromises = itemsToProcess.map(item => WorkflowCacheService.GetWFInfoAsync(item.tid));
494
- // Esegui tutte le chiamate in parallelo e attendi i risultati
495
- const setIDResults = await Promise.all(setIDPromises);
496
- const workflowInfoResults = await Promise.all(workflowInfoPromises);
497
- // Combina i risultati
498
- const finalWorkItems = itemsToProcess.map((item, index) => ({
499
- ...item,
500
- setID: setIDResults[index],
501
- }));
502
- const validWorkflows = workflowInfoResults.filter(Boolean);
503
- // Aggiorna lo stato una sola volta con i dati finali
504
- setWorkItems(finalWorkItems);
505
- setWorkflows(validWorkflows);
506
543
  }
507
544
  catch (error) {
545
+ // FASE 4: Gestione errori
508
546
  TMExceptionBoxManager.show({ exception: error });
509
547
  setWorkItems([]);
510
548
  setWorkflows([]);
511
549
  }
512
550
  finally {
551
+ // Garantisce sempre il reset del flag di loading
513
552
  setIsWFDataLoading(false);
514
553
  }
515
554
  };
516
- // Usa hasFormData invece di formDataRef.current
517
555
  if (!hasFormData || !fromDTD?.id) {
518
- // console.log("formData is empty or fromDTD not loaded, skipping loadAllWfData");
519
556
  return;
520
557
  }
521
558
  if (workItemSetIDValue !== undefined || workflowApproveData.length > 0)
522
559
  loadAllWfData();
523
- }, [hasFormData, workItemSetIDValue, workflowApproveData, DID, layoutMode, fromDTD?.templateTID, fromDTD?.id]);
560
+ }, [hasFormData, workItemSetIDValue, workflowApproveData, getWorkItemsByDID, TID, DID, layoutMode, fromDTD?.templateTID, fromDTD?.id]);
524
561
  const getSelectionDcmtInfo = useCallback(() => {
525
562
  let dcmts = [];
526
563
  dcmts.push({ TID: TID ?? 0, DID: DID ?? 0 });
@@ -551,7 +588,11 @@ const TMDcmtForm = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTa
551
588
  const showToppyForCompleteMoreInfo = useMemo(() => layoutMode === LayoutModes.Update && !!isTaskMoreInfo(taskMoreInfo?.name) && taskMoreInfo?.state !== Task_States.Completed, [layoutMode, taskMoreInfo?.name, taskMoreInfo?.state]);
552
589
  const showToppyForReferences = useMemo(() => allowButtonsRefs && layoutMode === LayoutModes.Update && !!(dcmtReferences && dcmtReferences.length > 0) && !isOpenDetails && !isOpenMaster, [allowButtonsRefs, layoutMode, dcmtReferences, isOpenDetails, isOpenMaster]);
553
590
  const isMobile = useMemo(() => deviceType === DeviceType.MOBILE, [deviceType]);
554
- const isApprView = useMemo(() => fromDTD?.templateTID === TemplateTIDs.WF_WIApprView, [fromDTD?.templateTID]);
591
+ const isApprView = useMemo(() => {
592
+ if (!fromDTD)
593
+ return false;
594
+ return isApprovalWorkflowView(fromDTD);
595
+ }, [fromDTD?.id]);
555
596
  const workitemSetID = useMemo(() => workItems.find(o => o.did === Number(DID))?.setID || formData.find(o => o.md?.name === WorkItemMetadataNames.WI_SetID)?.value, [workItems, DID, formData]);
556
597
  const approvalVID = useMemo(() => workItems.length > 0 ? Number(workItems[0].tid) : -1, [workItems]);
557
598
  //here
@@ -586,11 +627,12 @@ const TMDcmtForm = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTa
586
627
  disabled: false,
587
628
  onClick: () => {
588
629
  const dcmt = getDcmts()[0];
630
+ const name = `${fromDTD?.name ?? '-'} (DID: ${dcmt.DID})`;
589
631
  const taskContext = {
590
632
  document: {
591
633
  tid: dcmt.TID,
592
634
  did: dcmt.DID,
593
- name: fromDTD?.description || ''
635
+ name: name
594
636
  }
595
637
  };
596
638
  onTaskCreateRequest(taskContext);
@@ -1182,7 +1224,27 @@ const TMDcmtForm = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTa
1182
1224
  fontSize: '1.1rem',
1183
1225
  color: TMColors.primaryColor,
1184
1226
  textAlign: 'center',
1185
- }, children: SDKUI_Localizator.WorkflowDiagramNotAuthorized }))
1227
+ display: 'flex',
1228
+ flexDirection: 'column',
1229
+ alignItems: 'center',
1230
+ gap: '12px',
1231
+ }, children: _jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: '8px' }, children: [_jsx("span", { children: SDKUI_Localizator.WorkflowDiagramNotAuthorized }), wfError && (_jsx(TMTooltip, { content: 'Visualizza errore', children: _jsx("i", { className: "dx-icon-info", style: { fontSize: 20, cursor: 'pointer', color: '#dc3545' }, onClick: () => {
1232
+ TMMessageBoxManager.show({
1233
+ title: 'Dettagli Errore Workflow',
1234
+ initialWidth: !isMobile ? '700px' : undefined,
1235
+ message: (_jsx("pre", { style: {
1236
+ whiteSpace: 'pre-wrap',
1237
+ background: '#f5f5f5',
1238
+ padding: '12px',
1239
+ borderRadius: '6px',
1240
+ userSelect: 'text',
1241
+ cursor: 'text',
1242
+ }, children: wfError })),
1243
+ resizable: true,
1244
+ showToppy: false,
1245
+ buttons: [ButtonNames.OK],
1246
+ });
1247
+ } }) }))] }) }))
1186
1248
  : _jsx("div", { style: {
1187
1249
  position: 'absolute',
1188
1250
  top: '50%',
@@ -1442,7 +1504,7 @@ const TMDcmtForm = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTa
1442
1504
  } }), showApprovePopup && _jsx(WorkFlowApproveRejectPopUp, { deviceType: deviceType, onCompleted: handleWFOperationCompleted, TID: approvalVID, DID: DID, isReject: 0, onClose: () => setShowApprovePopup(false) }), showRejectPopup && _jsx(WorkFlowApproveRejectPopUp, { deviceType: deviceType, onCompleted: handleWFOperationCompleted, TID: approvalVID, DID: DID, isReject: 1, onClose: () => setShowRejectPopup(false) }), showReAssignPopup && _jsx(WorkFlowReAssignPopUp, { deviceType: deviceType, onCompleted: handleWFOperationCompleted, TID: approvalVID, DID: DID, onClose: () => setShowReAssignPopup(false) }), showMoreInfoPopup && _jsx(WorkFlowMoreInfoPopUp, { deviceType: deviceType, onCompleted: handleWFOperationCompleted, TID: approvalVID, DID: DID, onClose: () => setShowMoreInfoPopup(false) }), (isModal && onClose) && _jsx("div", { id: "TMDcmtFormShowConfirmForClose-" + id })] }) }), _jsx(ToppyDraggableHelpCenter, { initialIsCollapsed: false, deviceType: deviceType, isVisible: (showToppyForApprove || showToppyForCompleteMoreInfo || showToppyForReferences) && !openS4TViewer, content: _jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: '10px' }, children: [showToppyForApprove && (workItems.length === 1 ?
1443
1505
  _jsx(WorkFlowOperationButtons, { deviceType: deviceType, onApprove: () => setShowApprovePopup(true), onSignApprove: handleSignApprove, onReject: () => setShowRejectPopup(true), onReAssign: () => setShowReAssignPopup(true), onMoreInfo: () => setShowMoreInfoPopup(true), dtd: fromDTD })
1444
1506
  :
1445
- _jsxs("div", { style: { padding: 10, color: 'white', maxWidth: '180px', borderRadius: 10, background: '#1B1464 0% 0% no-repeat padding-box', border: '1px solid #FFFFFF' }, children: [`Devi approvare ${workItems.length} workitem(s) per questo documento.`, `Vai alla sezione di approvazione.`] })), showToppyForCompleteMoreInfo && (_jsxs(_Fragment, { children: [_jsx("div", { style: { padding: 10, color: 'white', maxWidth: '180px', borderRadius: 10, background: '#1B1464 0% 0% no-repeat padding-box', border: '1px solid #FFFFFF' }, children: `${SDKUI_Localizator.MoreInfoCompleteRequestSentBy} ${taskMoreInfo?.fromName}!` }), _jsx(TMButton, { caption: SDKUI_Localizator.CommentAndComplete, color: 'success', showTooltip: false, onClick: () => {
1507
+ _jsxs("div", { style: { padding: 10, color: 'white', maxWidth: '180px', borderRadius: 10, background: '#1B1464 0% 0% no-repeat padding-box', border: '1px solid #FFFFFF' }, children: [`Questo documento è associato a ${workItems.length} workitem.`, _jsx("br", {}), `Per approvare, vai alla pagina "Approvazione workflow".`] })), showToppyForCompleteMoreInfo && (_jsxs(_Fragment, { children: [_jsx("div", { style: { padding: 10, color: 'white', maxWidth: '180px', borderRadius: 10, background: '#1B1464 0% 0% no-repeat padding-box', border: '1px solid #FFFFFF' }, children: `${SDKUI_Localizator.MoreInfoCompleteRequestSentBy} ${taskMoreInfo?.fromName}!` }), _jsx(TMButton, { caption: SDKUI_Localizator.CommentAndComplete, color: 'success', showTooltip: false, onClick: () => {
1446
1508
  setShowCommentForm(true);
1447
1509
  } })] })), (showToppyForReferences && (dcmtReferences && dcmtReferences.length > 0)) && dcmtReferences
1448
1510
  .filter(ref => ref.objClass === ObjectClasses.Dossier || ref.objClass === ObjectClasses.WorkingGroup) // keep only known objClass types
@@ -1,9 +1,9 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
3
- import { SDK_Globals, DataColumnTypes, MetadataDataDomains, DataListViewModes, MetadataFormats, LayoutModes, TemplateTIDs, DcmtTypeListCacheService, SystemMIDsAsNumber, RetrieveFileOptions, DcmtOpers, GeneralRetrieveFormats, AccessLevelsEx, LayoutCacheService, UserListCacheService } from '@topconsultnpm/sdk-ts';
3
+ import { SDK_Globals, DataColumnTypes, MetadataDataDomains, DataListViewModes, MetadataFormats, LayoutModes, DcmtTypeListCacheService, SystemMIDsAsNumber, RetrieveFileOptions, DcmtOpers, GeneralRetrieveFormats, AccessLevelsEx, LayoutCacheService, UserListCacheService } from '@topconsultnpm/sdk-ts';
4
4
  import styled from 'styled-components';
5
5
  import { getAllFieldSelectedDcmtsOrFocused, getCommandsMenuItems, getSelectedDcmtsOrFocused } from './TMSearchResultsMenuItems';
6
- import { genUniqueId, IconShow, IconBoard, IconDcmtTypeSys, SDKUI_Localizator, IconDelete, IconRefresh, IconMenuVertical, deepCompare, generateUniqueColumnKeys, searchResultDescriptorToSimpleArray, searchResultToMetadataValues, IconSearchCheck, TMImageLibrary, convertSearchResultDescriptorToFileItems, IconCustom } from '../../../helper';
6
+ import { genUniqueId, IconShow, IconBoard, IconDcmtTypeSys, SDKUI_Localizator, IconDelete, IconRefresh, IconMenuVertical, deepCompare, generateUniqueColumnKeys, searchResultDescriptorToSimpleArray, searchResultToMetadataValues, IconSearchCheck, TMImageLibrary, convertSearchResultDescriptorToFileItems, IconCustom, isApprovalWorkflowView } from '../../../helper';
7
7
  import { useDcmtOperations } from '../../../hooks/useDcmtOperations';
8
8
  import { useInputAttachmentsDialog, useInputCvtFormatDialog } from '../../../hooks/useInputDialog';
9
9
  import { useRelatedDocuments } from '../../../hooks/useRelatedDocuments';
@@ -261,7 +261,7 @@ const TMSearchResult = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallback, a
261
261
  try {
262
262
  const dtd = await DcmtTypeListCacheService.GetWithNotGrantedAsync(item.TID, item?.DID);
263
263
  if (dtd) {
264
- const isWorkItem = dtd?.templateTID === TemplateTIDs.WF_WIApprView;
264
+ const isWorkItem = isApprovalWorkflowView(dtd);
265
265
  const name = `${dtd.name ?? '-'} (DID: ${item.DID})`;
266
266
  onTaskCreateRequest?.(isWorkItem
267
267
  ? { workItem: { tid: item.TID, did: item.DID, name } }
@@ -582,7 +582,9 @@ const TMSearchResult = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallback, a
582
582
  const handleSavedAsyncCallback = useCallback(async (tid, did, metadataResult) => {
583
583
  await refreshFocusedDataRowAsync(tid, did, true, metadataResult);
584
584
  }, [refreshFocusedDataRowAsync]);
585
- const showToppyForApprove = (isVisible && fromDTD?.templateTID === TemplateTIDs.WF_WIApprView && !isOpenDcmtForm && !isOpenDetails && !isOpenMaster);
585
+ const showToppyForApprove = useMemo(() => {
586
+ return Boolean(isVisible && fromDTD && isApprovalWorkflowView(fromDTD) && !isOpenDcmtForm && !isOpenDetails && !isOpenMaster);
587
+ }, [isVisible, fromDTD, isOpenDcmtForm, isOpenDetails, isOpenMaster]);
586
588
  const floatingMenuItems = useMemo(() => {
587
589
  return getCommandsMenuItems(isMobile, fromDTD, allUsers, selectedItems, focusedItem, context, showFloatingBar, workingGroupContext, showSearch, setShowFloatingBar, openFormHandler, openSharedArchiveHandler, showSharedDcmtsHandler, downloadDcmtsAsync, runOperationAsync, onRefreshSearchAsync, refreshSelectionDataRowsAsync, onRefreshAfterAddDcmtToFavs, confirmFormat, openConfirmAttachmentsDialog, openTaskFormHandler, openDetailDcmtsFormHandler, openMasterDcmtsFormHandler, openBatchUpdateFormHandler, openExportForm, handleToggleSearch, handleSignApprove, openSignSettingsForm, handleCheckOutOperationCallback, handleCheckInOperationCallback, showCheckoutInformationFormCallback, showHistoryCallback, copyCheckoutPathToClipboardOperationCallback, openWGsCopyMoveForm, openCommentFormCallback, openEditPdf, openAddDocumentForm, passToArchiveCallback, archiveMasterDocuments, archiveDetailDocuments, currentTIDHasMasterRelations, currentTIDHasDetailRelations, canArchiveMasterRelation, canArchiveDetailRelation, pairManyToMany, hasManyToManyRelation).concat([customButtonMenuItems()]);
588
590
  }, [
@@ -1,6 +1,6 @@
1
1
  import { Colors as ColorsType } from "../components/base/TMEditorBase";
2
2
  import { DeviceType } from "../components";
3
- import { AppModules, DataColumnDescriptor, ITopMediaSession, MetadataDescriptor, QueryDescriptor, SearchResultDescriptor } from "@topconsultnpm/sdk-ts";
3
+ import { AppModules, DataColumnDescriptor, DcmtTypeDescriptor, ITopMediaSession, MetadataDescriptor, QueryDescriptor, SearchResultDescriptor } from "@topconsultnpm/sdk-ts";
4
4
  import { FileExtensionHandler, FormModes, moduleTypes } from "../ts";
5
5
  declare const TABLET_WIDTH = 1024;
6
6
  declare const MOBILE_WIDTH = 640;
@@ -89,3 +89,4 @@ export declare class AreaHelper {
89
89
  static ExtractAreaInfo_1(areaPath: string): AreaValues;
90
90
  static ExtractAreaInfo_2(areaPath: string, extractFileName: boolean): AreaValues;
91
91
  }
92
+ export declare const isApprovalWorkflowView: (dtd: DcmtTypeDescriptor) => boolean;
@@ -1,7 +1,7 @@
1
1
  import { Fragment as _Fragment, jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
2
  import { Colors } from "../utils/theme";
3
3
  import { ButtonNames, DeviceType, TMExceptionBoxManager, TMMessageBoxManager, TMSpinner } from "../components";
4
- import { AccessLevels, MetadataDataDomains, MetadataDataTypes, MetadataDescriptor, MetadataFormatDescriptor, MetadataFormats, MetadataPermission, SDK_Globals, SetGlobalsInfoAsync, SystemMIDs, SystemMIDsAsNumber, TopMediaServer } from "@topconsultnpm/sdk-ts";
4
+ import { AccessLevels, MetadataDataDomains, MetadataDataTypes, MetadataDescriptor, MetadataFormatDescriptor, MetadataFormats, MetadataPermission, SDK_Globals, SetGlobalsInfoAsync, SystemMIDs, SystemMIDsAsNumber, TopMediaServer, WorkItemMetadataNames } from "@topconsultnpm/sdk-ts";
5
5
  import { Buffer } from 'buffer';
6
6
  import { buildTypes, FileExtensionHandler, FormModes, moduleTypes } from "../ts";
7
7
  import { SDKUI_Localizator } from "./SDKUI_Localizator";
@@ -856,3 +856,7 @@ export class AreaHelper {
856
856
  }
857
857
  AreaHelper.AreaPathPrefix = "tmarea:\\\\";
858
858
  AreaHelper.AreaFolderNamePrefix = "AID_";
859
+ export const isApprovalWorkflowView = (dtd) => {
860
+ return Boolean(dtd?.isView &&
861
+ dtd.metadata?.some(data => data.name === WorkItemMetadataNames.WI_DID));
862
+ };
@@ -8,4 +8,8 @@ export declare const useWorkflowApprove: () => {
8
8
  isLoading: boolean;
9
9
  refreshWorkflowApprove: () => Promise<void>;
10
10
  totalDcmtsFound: number;
11
+ getWorkItemsByDID: (targetDID: number) => {
12
+ tid: number;
13
+ did: number;
14
+ }[];
11
15
  };
@@ -14,6 +14,19 @@ export const useWorkflowApprove = () => {
14
14
  const calculateTotalDcmtsFound = useCallback((data) => {
15
15
  return data.reduce((sum, item) => sum + (item.dcmtsFound || 0), 0);
16
16
  }, []);
17
+ /**
18
+ * Ottiene tutti i work items che corrispondono a un determinato DID.
19
+ * Restituisce un array di oggetti { tid, did }.
20
+ */
21
+ const getWorkItemsByDID = useCallback((targetDID) => {
22
+ return workflowApproveData
23
+ .flatMap(workflow => workflow.dtdResult?.rows ?? [])
24
+ .filter(dataRow => Number(dataRow?.[1]) === targetDID)
25
+ .map(dataRow => ({
26
+ tid: Number(dataRow[0]),
27
+ did: targetDID
28
+ }));
29
+ }, [workflowApproveData]);
17
30
  /**
18
31
  * Esegue il fetch dei dati dal workflow, aggiorna lo stato globale
19
32
  * e notifica gli altri componenti tramite un evento.
@@ -53,5 +66,5 @@ export const useWorkflowApprove = () => {
53
66
  window.removeEventListener('onWorkflowApproveChange', handleUpdate);
54
67
  };
55
68
  }, [calculateTotalDcmtsFound]);
56
- return { workflowApproveData, isLoading, refreshWorkflowApprove, totalDcmtsFound };
69
+ return { workflowApproveData, isLoading, refreshWorkflowApprove, totalDcmtsFound, getWorkItemsByDID };
57
70
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@topconsultnpm/sdkui-react",
3
- "version": "6.20.0-dev1.44",
3
+ "version": "6.20.0-dev1.45",
4
4
  "description": "",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\" && exit 1",