@topconsultnpm/sdkui-react 6.20.0-dev1.43 → 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.
- package/lib/components/editors/TMMetadataValues.js +3 -3
- package/lib/components/features/documents/TMDcmtForm.d.ts +13 -1
- package/lib/components/features/documents/TMDcmtForm.js +125 -48
- package/lib/components/features/search/TMSearchResult.js +6 -4
- package/lib/components/features/workflow/diagram/WFDiagram.js +2 -2
- package/lib/components/index.d.ts +1 -0
- package/lib/components/index.js +1 -0
- package/lib/helper/helpers.d.ts +2 -1
- package/lib/helper/helpers.js +5 -1
- package/lib/hooks/useWorkflowApprove.d.ts +4 -0
- package/lib/hooks/useWorkflowApprove.js +14 -1
- package/package.json +1 -1
|
@@ -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,
|
|
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
|
|
571
|
+
if (isApprovalWorkflowView(currentDTD) && !isReadOnly) {
|
|
572
572
|
return layoutWorkItem;
|
|
573
573
|
}
|
|
574
574
|
switch (currentDTD?.id) {
|
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { HomeBlogPost, LayoutModes, ObjectRef, SearchResultDescriptor, TaskDescriptor, ValidationItem } from '@topconsultnpm/sdk-ts';
|
|
3
3
|
import { DcmtInfo, FormModes, MetadataValueDescriptorEx, TaskContext } from '../../../ts';
|
|
4
|
+
/**
|
|
5
|
+
* Definisce il contesto da cui è stato invocato il TMDcmtForm.
|
|
6
|
+
* Permette di gestire logiche diverse in base alla provenienza.
|
|
7
|
+
*/
|
|
8
|
+
export declare enum InvocationContext {
|
|
9
|
+
/** Invocazione standard */
|
|
10
|
+
Default = "default",
|
|
11
|
+
/** Invocato dalla pagina Todo/Task */
|
|
12
|
+
Todo = "todo",
|
|
13
|
+
/** Invocato dalla pagina WorkflowCtrl */
|
|
14
|
+
WorkflowCtrl = "workflowCtrl"
|
|
15
|
+
}
|
|
4
16
|
interface ITMDcmtFormProps {
|
|
5
17
|
allTasks?: Array<TaskDescriptor>;
|
|
6
18
|
getAllTasks?: () => Promise<void>;
|
|
@@ -24,7 +36,7 @@ interface ITMDcmtFormProps {
|
|
|
24
36
|
canPrev?: boolean;
|
|
25
37
|
isClosable?: boolean;
|
|
26
38
|
groupId?: string;
|
|
27
|
-
|
|
39
|
+
invocationContext?: InvocationContext;
|
|
28
40
|
taskFormDialogComponent?: React.ReactNode;
|
|
29
41
|
taskMoreInfo?: TaskDescriptor;
|
|
30
42
|
showBackButton?: boolean;
|
|
@@ -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,
|
|
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';
|
|
@@ -46,9 +46,24 @@ import TMViewHistoryDcmt from '../search/TMViewHistoryDcmt';
|
|
|
46
46
|
import TMDcmtCheckoutInfoForm from '../search/TMDcmtCheckoutInfoForm';
|
|
47
47
|
import styled from 'styled-components';
|
|
48
48
|
import { ContextMenu } from '../../NewComponents/ContextMenu';
|
|
49
|
+
//#region Interfaces, Types and Enums
|
|
50
|
+
/**
|
|
51
|
+
* Definisce il contesto da cui è stato invocato il TMDcmtForm.
|
|
52
|
+
* Permette di gestire logiche diverse in base alla provenienza.
|
|
53
|
+
*/
|
|
54
|
+
export var InvocationContext;
|
|
55
|
+
(function (InvocationContext) {
|
|
56
|
+
/** Invocazione standard */
|
|
57
|
+
InvocationContext["Default"] = "default";
|
|
58
|
+
/** Invocato dalla pagina Todo/Task */
|
|
59
|
+
InvocationContext["Todo"] = "todo";
|
|
60
|
+
/** Invocato dalla pagina WorkflowCtrl */
|
|
61
|
+
InvocationContext["WorkflowCtrl"] = "workflowCtrl";
|
|
62
|
+
// Aggiungi qui altri contesti futuri secondo necessità
|
|
63
|
+
})(InvocationContext || (InvocationContext = {}));
|
|
49
64
|
let abortControllerLocal = new AbortController();
|
|
50
65
|
//#endregion
|
|
51
|
-
const TMDcmtForm = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTaskCallback, editTaskCallback, handleNavigateToWGs, handleNavigateToDossiers, showHeader = true, onSaveRecents, layoutMode = LayoutModes.Update, showBackButton = true, onClose, onSavedAsyncCallback, TID, DID, formMode = FormModes.Update, canNext, canPrev, count, itemIndex, onNext, onPrev, allowNavigation = true, allowRelations = true, isClosable = false, isExpertMode = SDKUI_Globals.userSettings.advancedSettings.expertMode === 1, showDcmtFormSidebar = true,
|
|
66
|
+
const TMDcmtForm = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTaskCallback, editTaskCallback, handleNavigateToWGs, handleNavigateToDossiers, showHeader = true, onSaveRecents, layoutMode = LayoutModes.Update, showBackButton = true, onClose, onSavedAsyncCallback, TID, DID, formMode = FormModes.Update, canNext, canPrev, count, itemIndex, onNext, onPrev, allowNavigation = true, allowRelations = true, isClosable = false, isExpertMode = SDKUI_Globals.userSettings.advancedSettings.expertMode === 1, showDcmtFormSidebar = true, invocationContext = InvocationContext.Default, titleModal, isModal = false, widthModal = "100%", heightModal = "100%", groupId, onWFOperationCompleted, onTaskCompleted, onTaskCreateRequest, inputFile = null, taskFormDialogComponent, taskMoreInfo, connectorFileSave = undefined, inputMids = [], openS4TViewer = false, onOpenS4TViewerRequest, s4TViewerDialogComponent, enableDragDropOverlay = false, passToSearch, isSharedDcmt = false, sharedSourceTID, sharedSourceDID, allowButtonsRefs = false, onReferenceClick, }) => {
|
|
52
67
|
const { showHistory, showHistoryCallback, hideHistoryCallback, showCheckoutInformationForm, commentFormState, hideCommentFormCallback, showCheckoutInformationFormCallback, hideCheckoutInformationFormCallback, copyCheckoutPathToClipboardCallback, handleCheckOutCallback, handleCheckInCallback, refreshPreviewTrigger, showCicoWaitPanel, cicoWaitPanelTitle, showCicoPrimaryProgress, cicoPrimaryProgressText, cicoPrimaryProgressValue, cicoPrimaryProgressMax, } = useCheckInOutOperations();
|
|
53
68
|
const [id, setID] = useState('');
|
|
54
69
|
const [showWaitPanelLocal, setShowWaitPanelLocal] = useState(false);
|
|
@@ -104,6 +119,7 @@ const TMDcmtForm = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTa
|
|
|
104
119
|
const [dcmtReferences, setDcmtReferences] = useState(undefined);
|
|
105
120
|
// Stato per triggerare il refresh del blog dall'esterno
|
|
106
121
|
const [refreshBlogTrigger, setRefreshBlogTrigger] = useState(0);
|
|
122
|
+
const [wfError, setWfError] = useState(null);
|
|
107
123
|
const triggerBlogRefresh = useCallback(async () => {
|
|
108
124
|
setRefreshBlogTrigger(prev => prev + 1);
|
|
109
125
|
}, []);
|
|
@@ -120,7 +136,7 @@ const TMDcmtForm = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTa
|
|
|
120
136
|
}, [allowButtonsRefs]);
|
|
121
137
|
const { openConfirmAttachmentsDialog, ConfirmAttachmentsDialog } = useInputAttachmentsDialog();
|
|
122
138
|
const { abortController, showWaitPanel, waitPanelTitle, showPrimary, waitPanelTextPrimary, waitPanelValuePrimary, waitPanelMaxValuePrimary, showSecondary, waitPanelTextSecondary, waitPanelValueSecondary, waitPanelMaxValueSecondary, downloadDcmtsAsync, runOperationAsync } = useDcmtOperations();
|
|
123
|
-
const { workflowApproveData } = useWorkflowApprove();
|
|
139
|
+
const { workflowApproveData, getWorkItemsByDID } = useWorkflowApprove();
|
|
124
140
|
const currentSearchResults = useMemo(() => {
|
|
125
141
|
if (!formData || formData.length === 0 || !TID || !DID)
|
|
126
142
|
return [];
|
|
@@ -438,74 +454,110 @@ const TMDcmtForm = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTa
|
|
|
438
454
|
return;
|
|
439
455
|
copyCheckoutPathToClipboardCallback({ TID: currentDcmt.tid, DID: currentDcmt.did, FILEEXT: currentDcmt.fileExt }, fromDTD?.name ?? SDKUI_Localizator.SearchResult);
|
|
440
456
|
};
|
|
457
|
+
// useEffect per il caricamento dei dati del workflow
|
|
441
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
|
+
};
|
|
442
478
|
const loadAllWfData = async () => {
|
|
443
|
-
|
|
479
|
+
// FASE 1: Validazione prerequisiti
|
|
480
|
+
if (layoutMode !== LayoutModes.Update || !DID) {
|
|
444
481
|
setWorkItems([]);
|
|
445
482
|
setWorkflows([]);
|
|
446
483
|
return;
|
|
447
484
|
}
|
|
448
485
|
setIsWFDataLoading(true);
|
|
449
486
|
try {
|
|
450
|
-
//
|
|
451
|
-
const itemsToProcess =
|
|
452
|
-
|
|
453
|
-
for (const dataRow of workflow.dtdResult?.rows ?? []) {
|
|
454
|
-
const did = Number(dataRow?.[1]);
|
|
455
|
-
if (did === Number(DID)) {
|
|
456
|
-
const tid = Number(dataRow?.[0]);
|
|
457
|
-
itemsToProcess.push({ tid, did });
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
}
|
|
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
|
|
461
490
|
if (itemsToProcess.length === 0) {
|
|
462
491
|
setWorkItems([]);
|
|
463
492
|
setWorkflows([]);
|
|
464
493
|
setIsWFDataLoading(false);
|
|
465
494
|
return;
|
|
466
495
|
}
|
|
467
|
-
//
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
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);
|
|
472
515
|
}
|
|
473
516
|
else {
|
|
474
|
-
//
|
|
475
|
-
|
|
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
|
+
}
|
|
476
542
|
}
|
|
477
|
-
// Crea un array di Promise per tutte le chiamate a GetWFInfoAsync
|
|
478
|
-
const workflowInfoPromises = itemsToProcess.map(item => WorkflowCacheService.GetWFInfoAsync(item.tid));
|
|
479
|
-
// Esegui tutte le chiamate in parallelo e attendi i risultati
|
|
480
|
-
const setIDResults = await Promise.all(setIDPromises);
|
|
481
|
-
const workflowInfoResults = await Promise.all(workflowInfoPromises);
|
|
482
|
-
// Combina i risultati
|
|
483
|
-
const finalWorkItems = itemsToProcess.map((item, index) => ({
|
|
484
|
-
...item,
|
|
485
|
-
setID: setIDResults[index],
|
|
486
|
-
}));
|
|
487
|
-
const validWorkflows = workflowInfoResults.filter(Boolean);
|
|
488
|
-
// Aggiorna lo stato una sola volta con i dati finali
|
|
489
|
-
setWorkItems(finalWorkItems);
|
|
490
|
-
setWorkflows(validWorkflows);
|
|
491
543
|
}
|
|
492
544
|
catch (error) {
|
|
545
|
+
// FASE 4: Gestione errori
|
|
493
546
|
TMExceptionBoxManager.show({ exception: error });
|
|
494
547
|
setWorkItems([]);
|
|
495
548
|
setWorkflows([]);
|
|
496
549
|
}
|
|
497
550
|
finally {
|
|
551
|
+
// Garantisce sempre il reset del flag di loading
|
|
498
552
|
setIsWFDataLoading(false);
|
|
499
553
|
}
|
|
500
554
|
};
|
|
501
|
-
// Usa hasFormData invece di formDataRef.current
|
|
502
555
|
if (!hasFormData || !fromDTD?.id) {
|
|
503
|
-
// console.log("formData is empty or fromDTD not loaded, skipping loadAllWfData");
|
|
504
556
|
return;
|
|
505
557
|
}
|
|
506
558
|
if (workItemSetIDValue !== undefined || workflowApproveData.length > 0)
|
|
507
559
|
loadAllWfData();
|
|
508
|
-
}, [hasFormData, workItemSetIDValue, workflowApproveData, DID, layoutMode, fromDTD?.templateTID, fromDTD?.id]);
|
|
560
|
+
}, [hasFormData, workItemSetIDValue, workflowApproveData, getWorkItemsByDID, TID, DID, layoutMode, fromDTD?.templateTID, fromDTD?.id]);
|
|
509
561
|
const getSelectionDcmtInfo = useCallback(() => {
|
|
510
562
|
let dcmts = [];
|
|
511
563
|
dcmts.push({ TID: TID ?? 0, DID: DID ?? 0 });
|
|
@@ -536,7 +588,11 @@ const TMDcmtForm = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTa
|
|
|
536
588
|
const showToppyForCompleteMoreInfo = useMemo(() => layoutMode === LayoutModes.Update && !!isTaskMoreInfo(taskMoreInfo?.name) && taskMoreInfo?.state !== Task_States.Completed, [layoutMode, taskMoreInfo?.name, taskMoreInfo?.state]);
|
|
537
589
|
const showToppyForReferences = useMemo(() => allowButtonsRefs && layoutMode === LayoutModes.Update && !!(dcmtReferences && dcmtReferences.length > 0) && !isOpenDetails && !isOpenMaster, [allowButtonsRefs, layoutMode, dcmtReferences, isOpenDetails, isOpenMaster]);
|
|
538
590
|
const isMobile = useMemo(() => deviceType === DeviceType.MOBILE, [deviceType]);
|
|
539
|
-
const isApprView = useMemo(() =>
|
|
591
|
+
const isApprView = useMemo(() => {
|
|
592
|
+
if (!fromDTD)
|
|
593
|
+
return false;
|
|
594
|
+
return isApprovalWorkflowView(fromDTD);
|
|
595
|
+
}, [fromDTD?.id]);
|
|
540
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]);
|
|
541
597
|
const approvalVID = useMemo(() => workItems.length > 0 ? Number(workItems[0].tid) : -1, [workItems]);
|
|
542
598
|
//here
|
|
@@ -571,11 +627,12 @@ const TMDcmtForm = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTa
|
|
|
571
627
|
disabled: false,
|
|
572
628
|
onClick: () => {
|
|
573
629
|
const dcmt = getDcmts()[0];
|
|
630
|
+
const name = `${fromDTD?.name ?? '-'} (DID: ${dcmt.DID})`;
|
|
574
631
|
const taskContext = {
|
|
575
632
|
document: {
|
|
576
633
|
tid: dcmt.TID,
|
|
577
634
|
did: dcmt.DID,
|
|
578
|
-
name:
|
|
635
|
+
name: name
|
|
579
636
|
}
|
|
580
637
|
};
|
|
581
638
|
onTaskCreateRequest(taskContext);
|
|
@@ -1167,7 +1224,27 @@ const TMDcmtForm = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTa
|
|
|
1167
1224
|
fontSize: '1.1rem',
|
|
1168
1225
|
color: TMColors.primaryColor,
|
|
1169
1226
|
textAlign: 'center',
|
|
1170
|
-
|
|
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
|
+
} }) }))] }) }))
|
|
1171
1248
|
: _jsx("div", { style: {
|
|
1172
1249
|
position: 'absolute',
|
|
1173
1250
|
top: '50%',
|
|
@@ -1307,7 +1384,7 @@ const TMDcmtForm = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTa
|
|
|
1307
1384
|
// Checks if there's a saved panel layout for the current context (ToDo or general)
|
|
1308
1385
|
const hasSavedLayout = () => {
|
|
1309
1386
|
const { setting } = getCurrentDcmtFormSetting();
|
|
1310
|
-
if (
|
|
1387
|
+
if (invocationContext === InvocationContext.Todo) {
|
|
1311
1388
|
// If invoked by ToDo, check for existence of layoutToDo and that it has keys
|
|
1312
1389
|
return setting.layoutToDo !== undefined && Object.keys(setting.layoutToDo).length > 0;
|
|
1313
1390
|
}
|
|
@@ -1326,8 +1403,8 @@ const TMDcmtForm = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTa
|
|
|
1326
1403
|
// Prepare the new setting object with updated layout depending on context
|
|
1327
1404
|
const newSetting = {
|
|
1328
1405
|
TID: normalizedTID,
|
|
1329
|
-
layout:
|
|
1330
|
-
layoutToDo:
|
|
1406
|
+
layout: invocationContext === InvocationContext.Todo ? (existingSetting.layout ?? {}) : state,
|
|
1407
|
+
layoutToDo: invocationContext === InvocationContext.Todo ? state : (existingSetting.layoutToDo ?? {}),
|
|
1331
1408
|
};
|
|
1332
1409
|
// Replace existing setting if found, otherwise push a new one
|
|
1333
1410
|
if (idx >= 0) {
|
|
@@ -1346,7 +1423,7 @@ const TMDcmtForm = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTa
|
|
|
1346
1423
|
return undefined;
|
|
1347
1424
|
const settings = getCurrentDcmtFormSetting()?.setting;
|
|
1348
1425
|
// Return the appropriate layout based on context
|
|
1349
|
-
return
|
|
1426
|
+
return invocationContext === InvocationContext.Todo ? settings?.layoutToDo : settings?.layout;
|
|
1350
1427
|
};
|
|
1351
1428
|
const handleCompleteMoreInfo = useCallback(async () => {
|
|
1352
1429
|
try {
|
|
@@ -1427,7 +1504,7 @@ const TMDcmtForm = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTa
|
|
|
1427
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 ?
|
|
1428
1505
|
_jsx(WorkFlowOperationButtons, { deviceType: deviceType, onApprove: () => setShowApprovePopup(true), onSignApprove: handleSignApprove, onReject: () => setShowRejectPopup(true), onReAssign: () => setShowReAssignPopup(true), onMoreInfo: () => setShowMoreInfoPopup(true), dtd: fromDTD })
|
|
1429
1506
|
:
|
|
1430
|
-
_jsxs("div", { style: { padding: 10, color: 'white', maxWidth: '180px', borderRadius: 10, background: '#1B1464 0% 0% no-repeat padding-box', border: '1px solid #FFFFFF' }, children: [`
|
|
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: () => {
|
|
1431
1508
|
setShowCommentForm(true);
|
|
1432
1509
|
} })] })), (showToppyForReferences && (dcmtReferences && dcmtReferences.length > 0)) && dcmtReferences
|
|
1433
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,
|
|
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
|
|
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 = (
|
|
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
|
}, [
|
|
@@ -1656,10 +1656,10 @@ const WFDiagram = ({ xmlDiagramString, currentSetID, allowEdit = true, onDiagram
|
|
|
1656
1656
|
}
|
|
1657
1657
|
}, [wfDiagram]);
|
|
1658
1658
|
const handleCanvasDoubleClick = useCallback((event) => {
|
|
1659
|
-
if (isReadOnly) {
|
|
1659
|
+
if (isReadOnly && allowEdit) {
|
|
1660
1660
|
toggleReadOnlyMode();
|
|
1661
1661
|
}
|
|
1662
|
-
}, [isReadOnly, toggleReadOnlyMode]);
|
|
1662
|
+
}, [isReadOnly, allowEdit, toggleReadOnlyMode]);
|
|
1663
1663
|
const handleFullScreenKeyDown = useCallback((event) => {
|
|
1664
1664
|
if (event.key === 'Escape') {
|
|
1665
1665
|
// Blocca sempre la propagazione per evitare che TMSaveForm riceva l'evento
|
|
@@ -112,5 +112,6 @@ export * from "./features/workflow/diagram/WFDiagram";
|
|
|
112
112
|
export * from "./features/workflow/diagram/workflowHelpers";
|
|
113
113
|
export * from "./features/workflow/diagram/xmlParser";
|
|
114
114
|
export * from "./features/workflow/diagram/interfaces";
|
|
115
|
+
export * from "./features/workflow/diagram/DiagramItemSvgContent";
|
|
115
116
|
export { default as TMWizard } from './wizard/TMWizard';
|
|
116
117
|
export * from './wizard/TMWizard';
|
package/lib/components/index.js
CHANGED
|
@@ -133,6 +133,7 @@ export * from "./features/workflow/diagram/WFDiagram";
|
|
|
133
133
|
export * from "./features/workflow/diagram/workflowHelpers";
|
|
134
134
|
export * from "./features/workflow/diagram/xmlParser";
|
|
135
135
|
export * from "./features/workflow/diagram/interfaces";
|
|
136
|
+
export * from "./features/workflow/diagram/DiagramItemSvgContent";
|
|
136
137
|
// wizard
|
|
137
138
|
export { default as TMWizard } from './wizard/TMWizard';
|
|
138
139
|
export * from './wizard/TMWizard';
|
package/lib/helper/helpers.d.ts
CHANGED
|
@@ -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;
|
package/lib/helper/helpers.js
CHANGED
|
@@ -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
|
+
};
|
|
@@ -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
|
};
|