@topconsultnpm/sdkui-react 6.22.0-dev4.16 → 6.22.0-dev4.18
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/features/documents/TMDcmtForm.d.ts +6 -1
- package/lib/components/features/documents/TMDcmtForm.js +36 -6
- package/lib/components/features/documents/TMDcmtFormActionButtons.js +5 -2
- package/lib/components/features/documents/TMDcmtPreview.d.ts +2 -0
- package/lib/components/features/documents/TMDcmtPreview.js +10 -5
- package/lib/components/features/search/TMSearchResult.js +21 -4
- package/lib/components/features/workflow/TMWorkflowPopup.js +1 -1
- package/lib/helper/SDKUI_Globals.d.ts +1 -0
- package/lib/helper/SDKUI_Globals.js +1 -0
- package/lib/helper/queryHelper.d.ts +9 -2
- package/lib/helper/queryHelper.js +39 -1
- package/lib/hooks/useCaseFlowApprove.js +31 -6
- package/lib/services/caseflow/caseFlowNameCache.d.ts +5 -0
- package/lib/services/caseflow/caseFlowNameCache.js +19 -0
- package/package.json +1 -1
|
@@ -13,7 +13,12 @@ export declare enum InvocationContext {
|
|
|
13
13
|
/** Invocato dalla pagina Todo/Task */
|
|
14
14
|
Todo = "todo",
|
|
15
15
|
/** Invocato dalla pagina WorkflowCtrl */
|
|
16
|
-
WorkflowCtrl = "workflowCtrl"
|
|
16
|
+
WorkflowCtrl = "workflowCtrl",
|
|
17
|
+
/**
|
|
18
|
+
* Invocato dal dettaglio di una pratica: il Toppy non mostra le attività di
|
|
19
|
+
* pratica, perché la pratica le ha già nella propria barra azioni.
|
|
20
|
+
*/
|
|
21
|
+
CaseFlow = "caseFlow"
|
|
17
22
|
}
|
|
18
23
|
interface ITMDcmtFormProps {
|
|
19
24
|
TID?: number;
|
|
@@ -4,7 +4,7 @@ import TMDcmtPreview from './TMDcmtPreview';
|
|
|
4
4
|
import { AccessLevels, AccessLevelsEx, AppModules, ArchiveConstraints, ArchiveEngineByID, DcmtTypeDescriptor, DcmtTypeListCacheService, DcmtTypePermission, DossierCacheService, LayoutCacheService, LayoutModes, MetadataDataDomains, MetadataDataTypes, MetadataFormats, ObjectClasses, ResultTypes, SDK_Globals, SDK_Localizator, SystemMIDsAsNumber, SystemTIDs, Task_States, TID_DID, UpdateEngineByID, UserListCacheService, ValidationItem, WorkflowCacheService, WorkingGroupCacheService, WorkItemMetadataNames } from '@topconsultnpm/sdk-ts';
|
|
5
5
|
import { FormModes, SearchResultContext } from '../../../ts';
|
|
6
6
|
import { DeviceType, useDeviceType } from '../../base/TMDeviceProvider';
|
|
7
|
-
import { getWorkItemSetIDAsync, handleArchiveVisibility, searchResultToMetadataValues } from '../../../helper/queryHelper';
|
|
7
|
+
import { getDcmtMetadataValuesAsync, getTraceShowFileMids, getWorkItemSetIDAsync, handleArchiveVisibility, searchResultToMetadataValues } from '../../../helper/queryHelper';
|
|
8
8
|
import { genUniqueId, IconShow, SDKUI_Localizator, updateMruTids, IconBoard, IconDcmtTypeSys, calcIsModified, IconMenuVertical, Globalization, getListMaxItems, getSystemMetadata, IconBoxArchiveIn, IconClear, IconUndo, SDKUI_Globals, IconPreview, isTaskMoreInfo, IconWorkflow, IconSearch, deepCompare, IconActivity, getExceptionMessage, isApprovalWorkflowView, getDcmtCicoStatus, buildWorkItemsFromWFCtrl, IconLock, getDcmtFormToolbarVisibility, taskModalSizes, IconArchiveMultipleDetailDocuments, isNotGrantedDraftsDTD } from '../../../helper';
|
|
9
9
|
import { hasDetailRelations, hasMasterRelations } from '../../../helper/dcmtsHelper';
|
|
10
10
|
import { Gutters, TMColors } from '../../../utils/theme';
|
|
@@ -56,6 +56,11 @@ export var InvocationContext;
|
|
|
56
56
|
InvocationContext["Todo"] = "todo";
|
|
57
57
|
/** Invocato dalla pagina WorkflowCtrl */
|
|
58
58
|
InvocationContext["WorkflowCtrl"] = "workflowCtrl";
|
|
59
|
+
/**
|
|
60
|
+
* Invocato dal dettaglio di una pratica: il Toppy non mostra le attività di
|
|
61
|
+
* pratica, perché la pratica le ha già nella propria barra azioni.
|
|
62
|
+
*/
|
|
63
|
+
InvocationContext["CaseFlow"] = "caseFlow";
|
|
59
64
|
// Aggiungi qui altri contesti futuri secondo necessità
|
|
60
65
|
})(InvocationContext || (InvocationContext = {}));
|
|
61
66
|
let abortControllerLocal = new AbortController();
|
|
@@ -385,6 +390,29 @@ const TMDcmtForm = ({ TID, DID, groupId, layoutMode = LayoutModes.Update, formMo
|
|
|
385
390
|
const triggerPreviewRefresh = useCallback(async () => {
|
|
386
391
|
setRefreshPreviewTrigger(prev => prev + 1);
|
|
387
392
|
}, []);
|
|
393
|
+
// Dopo il recupero del file in anteprima aggiorna solo i metadati "Mostra file"
|
|
394
|
+
const refreshTraceShowFileMetadataAsync = useCallback(async () => {
|
|
395
|
+
const traceMids = getTraceShowFileMids(fromDTDRef.current);
|
|
396
|
+
if (!TID || !DID || traceMids.length === 0)
|
|
397
|
+
return;
|
|
398
|
+
try {
|
|
399
|
+
const res = await getDcmtMetadataValuesAsync(TID, DID, traceMids);
|
|
400
|
+
const row = res?.dtdResult?.rows?.[0];
|
|
401
|
+
const mids = res?.selectMIDs ?? [];
|
|
402
|
+
if (!row)
|
|
403
|
+
return;
|
|
404
|
+
// Anche l'originale, altrimenti il form risulterebbe modificato
|
|
405
|
+
const patchTraceValues = (list) => list.map(md => traceMids.includes(md.mid) && mids.includes(md.mid) ? { ...md, value: row[mids.indexOf(md.mid)] } : md);
|
|
406
|
+
setFormData(patchTraceValues);
|
|
407
|
+
setFormDataOrig(patchTraceValues);
|
|
408
|
+
formDataOrigRef.current = patchTraceValues(formDataOrigRef.current);
|
|
409
|
+
// Aggiorna anche la riga della griglia dei risultati con lo stesso risultato
|
|
410
|
+
await onSavedAsyncCallback?.(TID, DID, res);
|
|
411
|
+
}
|
|
412
|
+
catch (e) {
|
|
413
|
+
console.error('Errore aggiornamento metadati "Mostra file":', e);
|
|
414
|
+
}
|
|
415
|
+
}, [TID, DID, onSavedAsyncCallback]);
|
|
388
416
|
const openTaskFormHandler = (onTaskCreated) => {
|
|
389
417
|
if (!currentDcmt || !fromDTD)
|
|
390
418
|
return;
|
|
@@ -814,8 +842,10 @@ const TMDcmtForm = ({ TID, DID, groupId, layoutMode = LayoutModes.Update, formMo
|
|
|
814
842
|
return dcmtReferences.some(ref => ref.objClass === ObjectClasses.Dossier || ref.objClass === ObjectClasses.WorkingGroup);
|
|
815
843
|
}, [allowButtonsRefs, layoutMode, dcmtReferences, isOpenDetails, isOpenMaster]);
|
|
816
844
|
// Attività di pratica: stesse condizioni dell'approvazione workflow (documento
|
|
817
|
-
// in consultazione, senza errori, non dentro master/detail).
|
|
818
|
-
|
|
845
|
+
// in consultazione, senza errori, non dentro master/detail). Aperto dal
|
|
846
|
+
// dettaglio di una pratica, il form non le ripete.
|
|
847
|
+
const showToppyForCaseFlow = useMemo(() => layoutMode === LayoutModes.Update && !fetchError && caseFlowWorkItems.length > 0 && !isOpenDetails && !isOpenMaster
|
|
848
|
+
&& invocationContext !== InvocationContext.CaseFlow, [layoutMode, fetchError, caseFlowWorkItems.length, isOpenDetails, isOpenMaster, invocationContext]);
|
|
819
849
|
const isToppyVisible = useMemo(() => Boolean((showToppyForApprove || showToppyForCompleteMoreInfo || showToppyForReferences || showToppyForCaseFlow) && !openS4TViewer && !showTodoDcmtForm && !editPdfForm), [showToppyForApprove, showToppyForCompleteMoreInfo, showToppyForReferences, showToppyForCaseFlow, openS4TViewer, showTodoDcmtForm, editPdfForm]);
|
|
820
850
|
const handleClearForm = useCallback(() => {
|
|
821
851
|
let data = structuredClone(formData);
|
|
@@ -1262,7 +1292,7 @@ const TMDcmtForm = ({ TID, DID, groupId, layoutMode = LayoutModes.Update, formMo
|
|
|
1262
1292
|
]);
|
|
1263
1293
|
const tmBlog = useMemo(() => _jsx(TMDcmtBlog, { tid: TID, did: DID, fetchBlogDataTrigger: refreshBlogTrigger, onRefreshBlogDatagrid: onRefreshBlogDatagrid, allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback, editTaskCallback: editTaskCallback, handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers }), [TID, DID, allTasks, refreshBlogTrigger, handleNavigateToWGs, handleNavigateToDossiers]);
|
|
1264
1294
|
const tmSysMetadata = useMemo(() => _jsx(TMMetadataValues, { layoutMode: layoutMode, openChooserBySingleClick: !isOpenDistinctValues, TID: TID, isReadOnly: true, deviceType: deviceType, metadataValues: formData.filter(o => (o.mid != undefined && o.mid <= 100)), metadataValuesOrig: formData.filter(o => (o.mid != undefined && o.mid <= 100)), validationItems: [], inputMids: inputMids }), [TID, layoutMode, formData, deviceType, inputMids]);
|
|
1265
|
-
const tmDcmtPreview = useMemo(() => _jsx(TMDcmtPreviewWrapper, { refreshPreviewTrigger: refreshPreviewTrigger, fromDTD: fromDTD, currentDcmt: currentDcmt, dcmtFile: dcmtFile ?? inputFile, deviceType: deviceType, onBack: getOnBackHandler(), layoutMode: layoutMode, onFileUpload: (file) => { setDcmtFile(file); }, openFileUploaderPdfEditor: openFileUploaderPdfEditor, enableDragDropOverlay: enableDragDropOverlay, onScanRequest: onScanRequest }), [currentDcmt, dcmtFile, deviceType, fromDTD, layoutMode, inputFile, enableDragDropOverlay, setDcmtFile, onScanRequest, openFileUploaderPdfEditor, refreshPreviewTrigger]);
|
|
1295
|
+
const tmDcmtPreview = useMemo(() => _jsx(TMDcmtPreviewWrapper, { refreshPreviewTrigger: refreshPreviewTrigger, fromDTD: fromDTD, currentDcmt: currentDcmt, dcmtFile: dcmtFile ?? inputFile, deviceType: deviceType, onBack: getOnBackHandler(), layoutMode: layoutMode, onFileUpload: (file) => { setDcmtFile(file); }, openFileUploaderPdfEditor: openFileUploaderPdfEditor, enableDragDropOverlay: enableDragDropOverlay, onScanRequest: onScanRequest, onFileRetrieved: refreshTraceShowFileMetadataAsync }), [currentDcmt, dcmtFile, deviceType, fromDTD, layoutMode, inputFile, enableDragDropOverlay, setDcmtFile, onScanRequest, openFileUploaderPdfEditor, refreshPreviewTrigger, refreshTraceShowFileMetadataAsync]);
|
|
1266
1296
|
const tmWF = useMemo(() => {
|
|
1267
1297
|
if (isWFDataLoading) {
|
|
1268
1298
|
return (_jsx("div", { style: {
|
|
@@ -1868,11 +1898,11 @@ const PanelDisabledStateHandler = ({ isWFDisabled, isSysMetadataDisabled, isBoar
|
|
|
1868
1898
|
}, [isPreviewDisabled]);
|
|
1869
1899
|
return null;
|
|
1870
1900
|
};
|
|
1871
|
-
const TMDcmtPreviewWrapper = ({ refreshPreviewTrigger, fromDTD, currentDcmt, layoutMode, dcmtFile, deviceType, isVisible, onFileUpload, openFileUploaderPdfEditor, enableDragDropOverlay = false, onScanRequest, onBack }) => {
|
|
1901
|
+
const TMDcmtPreviewWrapper = ({ refreshPreviewTrigger, fromDTD, currentDcmt, layoutMode, dcmtFile, deviceType, isVisible, onFileUpload, openFileUploaderPdfEditor, enableDragDropOverlay = false, onScanRequest, onBack, onFileRetrieved }) => {
|
|
1872
1902
|
const { setPanelVisibilityById, toggleMaximize, isResizingActive, countVisibleLeafPanels, panelVisibility } = useTMPanelManagerContext();
|
|
1873
1903
|
const isMobile = deviceType === DeviceType.MOBILE;
|
|
1874
1904
|
return (layoutMode === LayoutModes.Update ?
|
|
1875
|
-
_jsx(TMDcmtPreview, { dcmtData: currentDcmt, isVisible: isVisible, onClosePanel: (!isMobile && countVisibleLeafPanels() > 1) ? () => setPanelVisibilityById('tmDcmtPreview', false) : undefined, allowMaximize: !isMobile && countVisibleLeafPanels() > 1, onMaximizePanel: (!isMobile && countVisibleLeafPanels() > 1) ? () => toggleMaximize("tmDcmtPreview") : undefined, onBack: onBack, isResizingActive: isResizingActive }, refreshPreviewTrigger) :
|
|
1905
|
+
_jsx(TMDcmtPreview, { dcmtData: currentDcmt, isVisible: isVisible, onClosePanel: (!isMobile && countVisibleLeafPanels() > 1) ? () => setPanelVisibilityById('tmDcmtPreview', false) : undefined, allowMaximize: !isMobile && countVisibleLeafPanels() > 1, onMaximizePanel: (!isMobile && countVisibleLeafPanels() > 1) ? () => toggleMaximize("tmDcmtPreview") : undefined, onBack: onBack, isResizingActive: isResizingActive, onFileRetrieved: onFileRetrieved }, refreshPreviewTrigger) :
|
|
1876
1906
|
_jsx(TMFileUploader, { fromDTD: fromDTD, onFileUpload: onFileUpload, openFileUploaderPdfEditor: openFileUploaderPdfEditor, onClose: (!isMobile && countVisibleLeafPanels() > 1) ? () => setPanelVisibilityById('tmDcmtPreview', false) : undefined, isRequired: fromDTD?.archiveConstraint === ArchiveConstraints.ContentCompulsory && dcmtFile === null, defaultBlob: dcmtFile, deviceType: deviceType, isResizingActive: isResizingActive, enableDragDropOverlay: panelVisibility['tmDcmtPreview'] && enableDragDropOverlay, onScanRequest: onScanRequest }));
|
|
1877
1907
|
};
|
|
1878
1908
|
const Ribbon = styled.div `
|
|
@@ -8,7 +8,7 @@ import TMButton from "../../base/TMButton";
|
|
|
8
8
|
import TMModal from "../../base/TMModal";
|
|
9
9
|
import TMTooltip from "../../base/TMTooltip";
|
|
10
10
|
import { WorkFlowOperationButtons } from "../workflow/TMWorkflowPopup";
|
|
11
|
-
import { getWorkItemActionName, isSignatureWorkItem } from "../../../services/caseflow/caseFlowWorkItemUtils";
|
|
11
|
+
import { getWorkItemActionName, isAcknowledgmentWorkItem, isSignatureWorkItem } from "../../../services/caseflow/caseFlowWorkItemUtils";
|
|
12
12
|
const TMDcmtFormActionButtons = (props) => {
|
|
13
13
|
const { showToppyForApprove, workItems, caseFlowWorkItems, onCompleteCaseFlowWorkItem, onRejectCaseFlowWorkItem, deviceType, isMobile, handleSignApprove, updateShowApprovePopup, updateShowRejectPopup, updateShowReAssignPopup, updateShowMoreInfoPopup, fromDTD, showToppyForCompleteMoreInfo, moreInfoTasks, setShowCommentForm, showToppyForReferences, dcmtReferences, referenceActionMap, handleNavigateToReference, setShowMoreInfoTaskPopup, setShowMoreInfoTaskTask } = props;
|
|
14
14
|
const [showAllMoreInfoModal, setShowAllMoreInfoModal] = useState(false);
|
|
@@ -103,7 +103,10 @@ const TMDcmtFormActionButtons = (props) => {
|
|
|
103
103
|
whiteSpace: 'pre-line',
|
|
104
104
|
}, children: description })), _jsx(WorkFlowOperationButtons, { dtd: fromDTD, deviceType: deviceType, signFlow: requiresSignature, approveDisable: isBusy, signApproveDisable: isBusy, rejectDisable: isBusy, onSignApprove: handleSignApprove, onApprove: onCompleteCaseFlowWorkItem
|
|
105
105
|
? () => void runCaseFlowAction(item, () => onCompleteCaseFlowWorkItem(item))
|
|
106
|
-
: undefined,
|
|
106
|
+
: undefined,
|
|
107
|
+
// La presa visione non si rifiuta, come nella pratica: senza
|
|
108
|
+
// handler il pulsante non viene mostrato.
|
|
109
|
+
onReject: onRejectCaseFlowWorkItem && !isAcknowledgmentWorkItem(workItem)
|
|
107
110
|
? () => { setRejectReason(''); setRejectingItem(item); }
|
|
108
111
|
: undefined })] }, workItem.id));
|
|
109
112
|
};
|
|
@@ -12,6 +12,8 @@ interface ITMDcmtPreviewProps {
|
|
|
12
12
|
onBack?: () => void;
|
|
13
13
|
allowMaximize?: boolean;
|
|
14
14
|
onMaximizePanel?: () => void;
|
|
15
|
+
/** File scaricato dal server con tracciatura "Mostra file": i metadati trace sono stati aggiornati */
|
|
16
|
+
onFileRetrieved?: (tid: number | undefined, did: number | undefined) => void;
|
|
15
17
|
}
|
|
16
18
|
declare const TMDcmtPreview: React.FC<ITMDcmtPreviewProps>;
|
|
17
19
|
export default TMDcmtPreview;
|
|
@@ -22,7 +22,7 @@ const ErrorContent = ({ error, isAbortError, onRetry }) => {
|
|
|
22
22
|
}
|
|
23
23
|
return _jsx(TMNothingToShow, { icon: _jsx(IconCloseOutline, { fontSize: 92, color: TMColors.error }), text: error });
|
|
24
24
|
};
|
|
25
|
-
const TMDcmtPreview = ({ dcmtData, isResizingActive, isVisible, canNext, canPrev, onClosePanel, onBack, onNext, onPrev, allowMaximize = true, onMaximizePanel }) => {
|
|
25
|
+
const TMDcmtPreview = ({ dcmtData, isResizingActive, isVisible, canNext, canPrev, onClosePanel, onBack, onNext, onPrev, allowMaximize = true, onMaximizePanel, onFileRetrieved }) => {
|
|
26
26
|
const [dcmtBlob, setDcmtBlob] = useState(undefined);
|
|
27
27
|
const [showPreview, setShowPreview] = useState(false);
|
|
28
28
|
const [isFromCache, setIsFromCache] = useState(false);
|
|
@@ -122,20 +122,25 @@ const TMDcmtPreview = ({ dcmtData, isResizingActive, isVisible, canNext, canPrev
|
|
|
122
122
|
}
|
|
123
123
|
}
|
|
124
124
|
};
|
|
125
|
-
|
|
125
|
+
/** @param isShown false se a video resta la richiesta di conferma: il file non è visualizzato */
|
|
126
|
+
const loadDocumentWithCache = async (isShown = true) => {
|
|
126
127
|
const rfo = new RetrieveFileOptions();
|
|
127
|
-
|
|
128
|
+
// Senza impostazione salvata l'anteprima non aggiorna la tracciatura "Mostra file"
|
|
129
|
+
rfo.retrieveReason = isShown && SDKUI_Globals.userSettings?.searchSettings?.previewTracksShowFile === true ? DcmtOpers.ShowFile : DcmtOpers.None;
|
|
128
130
|
rfo.generalRetrieveFormat = GeneralRetrieveFormats.OriginalUnsigned;
|
|
129
131
|
rfo.cvtFormat = extensionHandler(dcmtData?.fileExt) === FileExtensionHandler.CONVERTIBLE ? FileFormats.PDF : FileFormats.None;
|
|
130
132
|
rfo.invoiceRetrieveFormat = SDKUI_Globals.userSettings?.searchSettings.invoiceRetrieveFormat;
|
|
131
133
|
rfo.orderRetrieveFormat = SDKUI_Globals.userSettings?.searchSettings.orderRetrieveFormat;
|
|
132
134
|
try {
|
|
133
135
|
await sleep(300); //wait for DX-DataGrid selectionChanged
|
|
134
|
-
let dcmtFile = await getDcmtFileAsync({ TID: dcmtData?.tid, DID: dcmtData?.did, FILEEXT: dcmtData?.fileExt }, rfo, 'Anteprima', false);
|
|
136
|
+
let dcmtFile = await getDcmtFileAsync({ TID: dcmtData?.tid, DID: dcmtData?.did, FILEEXT: dcmtData?.fileExt }, rfo, 'Anteprima', false, !isShown);
|
|
135
137
|
setDcmtBlob(dcmtFile?.file);
|
|
136
138
|
setIsFromCache(!!dcmtFile?.isFromCache);
|
|
137
139
|
setError('');
|
|
138
140
|
setIsAbortError(false);
|
|
141
|
+
// Dalla cache l'API non è stata chiamata: la tracciatura non è cambiata
|
|
142
|
+
if (dcmtFile?.file && !dcmtFile.isFromCache && rfo.retrieveReason === DcmtOpers.ShowFile)
|
|
143
|
+
onFileRetrieved?.(dcmtData?.tid, dcmtData?.did);
|
|
139
144
|
}
|
|
140
145
|
catch (ex) {
|
|
141
146
|
const err = ex;
|
|
@@ -179,7 +184,7 @@ const TMDcmtPreview = ({ dcmtData, isResizingActive, isVisible, canNext, canPrev
|
|
|
179
184
|
setIsAbortError(false);
|
|
180
185
|
setDcmtBlob(undefined);
|
|
181
186
|
try {
|
|
182
|
-
isBasketMode ? await loadBasketFile() : await loadDocumentWithCache();
|
|
187
|
+
isBasketMode ? await loadBasketFile() : await loadDocumentWithCache(showPreview);
|
|
183
188
|
}
|
|
184
189
|
catch (error) {
|
|
185
190
|
console.error('Error reopening document:', error);
|
|
@@ -3,7 +3,7 @@ import React, { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useSta
|
|
|
3
3
|
import styled from 'styled-components';
|
|
4
4
|
import { LoadIndicator } from 'devextreme-react';
|
|
5
5
|
import { AppModules, DataColumnTypes, DataListViewModes, DcmtTypeListCacheService, LayoutCacheService, LayoutModes, MetadataDataDomains, SDK_Globals, SystemMIDsAsNumber, UserListCacheService, } from '@topconsultnpm/sdk-ts';
|
|
6
|
-
import { customizeSearchByDisplayText, deepCompare, formatDateTimeByMetadataFormat, formatNumberByMetadataFormat, generateUniqueColumnKeys, genUniqueId, getColumnFormatInfo, getDateDisplayText, getNumberDisplayText, getSearchToolbarVisibility, IconAll, IconBoard, IconDcmtTypeSys, IconDelete, IconDuplicate, IconEdit, IconMenuVertical, IconPlatform, IconRefresh, IconSearchCheck, IconShow, isApprovalWorkflowView, isSign4TopEnabled, searchResultDescriptorToSimpleArray, searchResultToMetadataValues, SDKUI_Globals, SDKUI_Localizator, IconCloseOutline, getSearchResultPanelLayout, getSearchResultPanelLayoutSignature, hasSearchResultPanelLayout, saveSearchResultPanelLayout, subscribeSearchResultPanelLayout, VIRTUAL_RENDERING_THRESHOLD, VIRTUAL_RENDERING_CELL_THRESHOLD } from '../../../helper';
|
|
6
|
+
import { customizeSearchByDisplayText, deepCompare, formatDateTimeByMetadataFormat, formatNumberByMetadataFormat, generateUniqueColumnKeys, genUniqueId, getColumnFormatInfo, getDateDisplayText, getNumberDisplayText, getSearchToolbarVisibility, IconAll, IconBoard, IconDcmtTypeSys, IconDelete, IconDuplicate, IconEdit, IconMenuVertical, IconPlatform, IconRefresh, IconSearchCheck, IconShow, isApprovalWorkflowView, isSign4TopEnabled, searchResultDescriptorToSimpleArray, searchResultToMetadataValues, getTraceShowFileMids, getDcmtMetadataValuesAsync, SDKUI_Globals, SDKUI_Localizator, IconCloseOutline, getSearchResultPanelLayout, getSearchResultPanelLayoutSignature, hasSearchResultPanelLayout, saveSearchResultPanelLayout, subscribeSearchResultPanelLayout, VIRTUAL_RENDERING_THRESHOLD, VIRTUAL_RENDERING_CELL_THRESHOLD } from '../../../helper';
|
|
7
7
|
import { CounterItemKey, formatCount } from '../../base/TMCounterContainer';
|
|
8
8
|
import { getDcmtCicoStatus } from '../../../helper/checkinCheckoutManager';
|
|
9
9
|
import { DcmtOperationTypes, SearchResultContext, } from '../../../ts';
|
|
@@ -285,6 +285,23 @@ handleNavigateToWGs, handleNavigateToDossiers, fetchRemoteCertificates, graphome
|
|
|
285
285
|
if (refreshUI)
|
|
286
286
|
setLastUpdateSearchTime(new Date(Date.now()));
|
|
287
287
|
};
|
|
288
|
+
// Ref alla versione corrente: l'anteprima è memoizzata e la funzione si ricrea a ogni render
|
|
289
|
+
const refreshFocusedDataRowRef = useRef(refreshFocusedDataRowAsync);
|
|
290
|
+
refreshFocusedDataRowRef.current = refreshFocusedDataRowAsync;
|
|
291
|
+
// Anteprima scaricata dal server con tracciatura "Mostra file": aggiorna solo la riga del documento
|
|
292
|
+
const onPreviewFileRetrieved = useCallback(async (tid, did) => {
|
|
293
|
+
const traceMids = getTraceShowFileMids(fromDTD);
|
|
294
|
+
if (!tid || !did || traceMids.length === 0)
|
|
295
|
+
return;
|
|
296
|
+
try {
|
|
297
|
+
const res = await getDcmtMetadataValuesAsync(tid, did, traceMids);
|
|
298
|
+
if (res)
|
|
299
|
+
await refreshFocusedDataRowRef.current(tid, did, true, res);
|
|
300
|
+
}
|
|
301
|
+
catch (e) {
|
|
302
|
+
console.error('Errore aggiornamento metadati "Mostra file":', e);
|
|
303
|
+
}
|
|
304
|
+
}, [fromDTD]);
|
|
288
305
|
// Refreshes metadata for selected documents (or focused one) and triggers grid re-render
|
|
289
306
|
const onRefreshDataRowsAsync = async () => {
|
|
290
307
|
let dcmts = getSelectedDcmtsOrFocused(selectedItems, focusedItem);
|
|
@@ -829,7 +846,7 @@ handleNavigateToWGs, handleNavigateToDossiers, fetchRemoteCertificates, graphome
|
|
|
829
846
|
const isSearchResultOnScreen = isVisible && !isOpenDcmtForm && !isOpenDetails && !isOpenMaster;
|
|
830
847
|
const tmBlog = useMemo(() => _jsx(TMDcmtBlog, { tid: focusedItem?.TID, did: focusedItem?.DID, isPageVisible: isSearchResultOnScreen, fetchBlogDataTrigger: refreshBlogTrigger, allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback, editTaskCallback: editTaskCallback, handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers }), [focusedItem, allTasks, refreshBlogTrigger, isSearchResultOnScreen, handleNavigateToWGs, handleNavigateToDossiers, onRefreshBlogDatagrid]);
|
|
831
848
|
const tmSysMetadata = useMemo(() => _jsx(TMMetadataValues, { layoutMode: LayoutModes.Update, openChooserBySingleClick: true, TID: focusedItem?.TID, isReadOnly: true, deviceType: deviceType, metadataValues: currentMetadataValues.filter(o => (o.mid != undefined && o.mid <= 100)), metadataValuesOrig: currentMetadataValues.filter(o => (o.mid != undefined && o.mid <= 100)), validationItems: [] }), [focusedItem, currentMetadataValues, deviceType]);
|
|
832
|
-
const tmDcmtPreview = useMemo(() => _jsx(TMDcmtPreviewWrapper, { refreshPreviewTrigger: refreshPreviewTrigger, currentDcmt: currentDcmt, isPageVisible: isSearchResultOnScreen, onBack: backHandlerSecondary }), [currentDcmt, refreshPreviewTrigger, isSearchResultOnScreen, backHandlerSecondary]);
|
|
849
|
+
const tmDcmtPreview = useMemo(() => _jsx(TMDcmtPreviewWrapper, { refreshPreviewTrigger: refreshPreviewTrigger, currentDcmt: currentDcmt, isPageVisible: isSearchResultOnScreen, onBack: backHandlerSecondary, onFileRetrieved: onPreviewFileRetrieved }), [currentDcmt, refreshPreviewTrigger, isSearchResultOnScreen, backHandlerSecondary, onPreviewFileRetrieved]);
|
|
833
850
|
// Auto-fetch indexing info when drawer is open and focusedItem changes
|
|
834
851
|
useEffect(() => {
|
|
835
852
|
if (!focusedItem || !showIndexingInfo)
|
|
@@ -1746,11 +1763,11 @@ const PanelDisabledStateHandler = ({ isBoardDisabled, savedBlogVisible = false }
|
|
|
1746
1763
|
}, [isBoardDisabled, savedBlogVisible]);
|
|
1747
1764
|
return null;
|
|
1748
1765
|
};
|
|
1749
|
-
const TMDcmtPreviewWrapper = ({ refreshPreviewTrigger, currentDcmt, isVisible, isPageVisible = true, onBack }) => {
|
|
1766
|
+
const TMDcmtPreviewWrapper = ({ refreshPreviewTrigger, currentDcmt, isVisible, isPageVisible = true, onBack, onFileRetrieved }) => {
|
|
1750
1767
|
const { setPanelVisibilityById, toggleMaximize, isResizingActive, countVisibleLeafPanels } = useTMPanelManagerContext();
|
|
1751
1768
|
const deviceType = useDeviceType();
|
|
1752
1769
|
const isMobile = deviceType === DeviceType.MOBILE;
|
|
1753
|
-
return (_jsx(TMDcmtPreview, { dcmtData: currentDcmt, onClosePanel: (!isMobile && countVisibleLeafPanels() > 1) ? () => setPanelVisibilityById('tmDcmtPreview', false) : undefined, onBack: onBack, allowMaximize: !isMobile && countVisibleLeafPanels() > 1, onMaximizePanel: (!isMobile && countVisibleLeafPanels() > 1) ? () => toggleMaximize("tmDcmtPreview") : undefined, isResizingActive: isResizingActive, isVisible: isVisible && isPageVisible }, refreshPreviewTrigger));
|
|
1770
|
+
return (_jsx(TMDcmtPreview, { dcmtData: currentDcmt, onClosePanel: (!isMobile && countVisibleLeafPanels() > 1) ? () => setPanelVisibilityById('tmDcmtPreview', false) : undefined, onBack: onBack, allowMaximize: !isMobile && countVisibleLeafPanels() > 1, onMaximizePanel: (!isMobile && countVisibleLeafPanels() > 1) ? () => toggleMaximize("tmDcmtPreview") : undefined, isResizingActive: isResizingActive, isVisible: isVisible && isPageVisible, onFileRetrieved: onFileRetrieved }, refreshPreviewTrigger));
|
|
1754
1771
|
};
|
|
1755
1772
|
// Styled Components
|
|
1756
1773
|
const StyledPlaceholder = styled.div `
|
|
@@ -66,7 +66,7 @@ export const WorkFlowOperationButtons = (props) => {
|
|
|
66
66
|
}
|
|
67
67
|
return false;
|
|
68
68
|
}, [dtd, signFlow]);
|
|
69
|
-
return (_jsx(StyledWorkFlowOperationButtonsContainer, { $isMobile: isMobile, children: isSignWorkflow ? (_jsxs(_Fragment, { children: [_jsx(TMButton, { btnStyle: isMobile ? 'toolbar' : 'advanced', showTooltip: isMobile, icon: _jsx(IconSignaturePencil, {}), caption: SDKUI_Localizator.SignatureAndApprove, width: "160px", disabled: signApproveDisable, onClick: () => !signApproveDisable && onSignApprove?.(), onMouseDown: e => e.stopPropagation(), advancedColor: "#1a9a49", color: "success" }), _jsx(TMButton, { btnStyle: isMobile ? 'toolbar' : 'advanced', showTooltip: isMobile, icon: _jsx(IconCloseOutline, {}), caption: SDKUI_Localizator.Reject, disabled: rejectDisable, onClick: () => !rejectDisable && onReject?.(), onMouseDown: e => e.stopPropagation(), advancedColor: TMColors.error, color: "error" }), onMoreInfo && (_jsx(TMButton, { btnStyle: isMobile ? 'toolbar' : 'advanced', showTooltip: isMobile, icon: _jsx(IconInfo, { fontSize: 16 }), caption: SDKUI_Localizator.MoreInformation, width: "180px", disabled: infoDisable, onClick: () => !infoDisable && onMoreInfo?.(), onMouseDown: e => e.stopPropagation(), advancedColor: TMColors.info, color: "info" }))] })) : (_jsxs(_Fragment, { children: [_jsx(TMButton, { btnStyle: isMobile ? 'toolbar' : 'advanced', showTooltip: isMobile, icon: _jsx(IconApply, {}), caption: SDKUI_Localizator.Approve, disabled: approveDisable, onClick: () => !approveDisable && onApprove?.(), advancedColor: "#1a9a49", color: "success" }), _jsx(TMButton, { btnStyle: isMobile ? 'toolbar' : 'advanced', showTooltip: isMobile, icon: _jsx(IconCloseOutline, {}), caption: SDKUI_Localizator.Reject, disabled: rejectDisable, onClick: () => !rejectDisable && onReject?.(), advancedColor: TMColors.error, color: "error" }), onReAssign && (_jsx(TMButton, { btnStyle: isMobile ? 'toolbar' : 'advanced', showTooltip: isMobile, icon: _jsx(IconUser, { fontSize: 16 }), caption: SDKUI_Localizator.Reassign, disabled: reassignDisable, onClick: () => !reassignDisable && onReAssign?.(), advancedColor: TMColors.tertiary, color: "tertiary" })), onMoreInfo && (_jsx(TMButton, { btnStyle: isMobile ? 'toolbar' : 'advanced', showTooltip: isMobile, icon: _jsx(IconInfo, { fontSize: 16 }), caption: SDKUI_Localizator.MoreInformation, width: "180px", disabled: infoDisable, onClick: () => !infoDisable && onMoreInfo?.(), advancedColor: TMColors.info, color: "info" }))] })) }));
|
|
69
|
+
return (_jsx(StyledWorkFlowOperationButtonsContainer, { $isMobile: isMobile, children: isSignWorkflow ? (_jsxs(_Fragment, { children: [_jsx(TMButton, { btnStyle: isMobile ? 'toolbar' : 'advanced', showTooltip: isMobile, icon: _jsx(IconSignaturePencil, {}), caption: SDKUI_Localizator.SignatureAndApprove, width: "160px", disabled: signApproveDisable, onClick: () => !signApproveDisable && onSignApprove?.(), onMouseDown: e => e.stopPropagation(), advancedColor: "#1a9a49", color: "success" }), onReject && (_jsx(TMButton, { btnStyle: isMobile ? 'toolbar' : 'advanced', showTooltip: isMobile, icon: _jsx(IconCloseOutline, {}), caption: SDKUI_Localizator.Reject, disabled: rejectDisable, onClick: () => !rejectDisable && onReject?.(), onMouseDown: e => e.stopPropagation(), advancedColor: TMColors.error, color: "error" })), onMoreInfo && (_jsx(TMButton, { btnStyle: isMobile ? 'toolbar' : 'advanced', showTooltip: isMobile, icon: _jsx(IconInfo, { fontSize: 16 }), caption: SDKUI_Localizator.MoreInformation, width: "180px", disabled: infoDisable, onClick: () => !infoDisable && onMoreInfo?.(), onMouseDown: e => e.stopPropagation(), advancedColor: TMColors.info, color: "info" }))] })) : (_jsxs(_Fragment, { children: [_jsx(TMButton, { btnStyle: isMobile ? 'toolbar' : 'advanced', showTooltip: isMobile, icon: _jsx(IconApply, {}), caption: SDKUI_Localizator.Approve, disabled: approveDisable, onClick: () => !approveDisable && onApprove?.(), advancedColor: "#1a9a49", color: "success" }), onReject && (_jsx(TMButton, { btnStyle: isMobile ? 'toolbar' : 'advanced', showTooltip: isMobile, icon: _jsx(IconCloseOutline, {}), caption: SDKUI_Localizator.Reject, disabled: rejectDisable, onClick: () => !rejectDisable && onReject?.(), advancedColor: TMColors.error, color: "error" })), onReAssign && (_jsx(TMButton, { btnStyle: isMobile ? 'toolbar' : 'advanced', showTooltip: isMobile, icon: _jsx(IconUser, { fontSize: 16 }), caption: SDKUI_Localizator.Reassign, disabled: reassignDisable, onClick: () => !reassignDisable && onReAssign?.(), advancedColor: TMColors.tertiary, color: "tertiary" })), onMoreInfo && (_jsx(TMButton, { btnStyle: isMobile ? 'toolbar' : 'advanced', showTooltip: isMobile, icon: _jsx(IconInfo, { fontSize: 16 }), caption: SDKUI_Localizator.MoreInformation, width: "180px", disabled: infoDisable, onClick: () => !infoDisable && onMoreInfo?.(), advancedColor: TMColors.info, color: "info" }))] })) }));
|
|
70
70
|
};
|
|
71
71
|
export const WorkFlowApproveRejectPopUp = ({ TID = 0, DID = 0, deviceType = DeviceType.DESKTOP, isReject, selectedItems = [], onClose, onCompleted }) => {
|
|
72
72
|
const { refreshWorkflowApprove } = useWorkflowApprove();
|
|
@@ -158,6 +158,7 @@ export class SearchSettings {
|
|
|
158
158
|
this.mruTIDs = [];
|
|
159
159
|
this.defaultTree = -1;
|
|
160
160
|
this.previewThreshold = DEFAULT_PREVIEW_THRESHOLD;
|
|
161
|
+
this.previewTracksShowFile = false; // Se attivo, l'anteprima aggiorna la tracciatura "Mostra file" del documento
|
|
161
162
|
this.pageSize = DEFAULT_PAGE_SIZE;
|
|
162
163
|
this.maxDcmtsToBeReturned = DEFAULT_MAX_DCMTS_TO_BE_RETURNED;
|
|
163
164
|
this.floatingMenuBar = new FloatingMenuBarSettings();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { MetadataDescriptor, MetadataDataDomains, SystemMIDsAsNumber, MetadataDataTypes, QueryDescriptor, SelectItem, DataTableDescriptor, LayoutModes, QueryOperators, SavedQueryDescriptor } from '@topconsultnpm/sdk-ts';
|
|
1
|
+
import { MetadataDescriptor, MetadataDataDomains, SystemMIDsAsNumber, MetadataDataTypes, QueryDescriptor, SelectItem, DataTableDescriptor, LayoutModes, QueryOperators, SavedQueryDescriptor, DcmtTypeDescriptor, SearchResultDescriptor } from '@topconsultnpm/sdk-ts';
|
|
2
2
|
import { MetadataValueDescriptorEx } from '../ts';
|
|
3
3
|
export type TID_Alias = {
|
|
4
4
|
tid: number;
|
|
@@ -8,7 +8,7 @@ export declare const getTIDsByQd: (qd: QueryDescriptor | undefined) => TID_Alias
|
|
|
8
8
|
/** Restituisce i tipi documento (con metadati) referenziati da qd.
|
|
9
9
|
* Con refreshCache = true i descrittori vengono riletti dal server, così la lista dei metadati
|
|
10
10
|
* recepisce quelli aggiunti o rimossi dopo il popolamento della cache. */
|
|
11
|
-
export declare const getDcmtTypesByQdAsync: (qd: QueryDescriptor, refreshCache?: boolean) => Promise<
|
|
11
|
+
export declare const getDcmtTypesByQdAsync: (qd: QueryDescriptor, refreshCache?: boolean) => Promise<DcmtTypeDescriptor[]>;
|
|
12
12
|
export declare const displayMetadataValue: (md: MetadataDescriptor | undefined, value: string | undefined, valueEmptyDescription?: string) => string;
|
|
13
13
|
export declare const IsParametricQuery: (qd: QueryDescriptor | undefined) => boolean;
|
|
14
14
|
export declare const addHiddenSelectItem: (select: SelectItem[], tid: number | undefined, mid: SystemMIDsAsNumber) => void;
|
|
@@ -20,5 +20,12 @@ export declare const getWorkItemSetIDAsync: (vid: number, did: number) => Promis
|
|
|
20
20
|
/** Id assegnato alla ricerca di sistema con tutti i documenti: non è in cache, va ricostruita a runtime con getSysAllDcmtsSQD */
|
|
21
21
|
export declare const SYS_ALL_DCMTS_SQD_ID = 1;
|
|
22
22
|
export declare const getSysAllDcmtsSQD: (tid: number | undefined, easyOr: boolean) => Promise<SavedQueryDescriptor>;
|
|
23
|
+
/** MID dei metadati con tracciatura "Mostra file" del tipo documento */
|
|
24
|
+
export declare const getTraceShowFileMids: (dtd: DcmtTypeDescriptor | undefined) => number[];
|
|
25
|
+
/**
|
|
26
|
+
* Legge solo i metadati indicati del documento con una ricerca mirata.
|
|
27
|
+
* Se la ricerca fallisce o non li restituisce tutti (es. permessi), ripiega sulla GetMetadata completa.
|
|
28
|
+
*/
|
|
29
|
+
export declare const getDcmtMetadataValuesAsync: (tid: number, did: number, mids: number[]) => Promise<SearchResultDescriptor | undefined>;
|
|
23
30
|
export declare const searchResultToMetadataValues: (tid: number | undefined, dtd: DataTableDescriptor | undefined, rows: string[], mids: number[], metadata: MetadataDescriptor[], layoutMode: LayoutModes, isReadOnlyOrigin?: boolean) => MetadataValueDescriptorEx[];
|
|
24
31
|
export declare const handleArchiveVisibility: (md: MetadataDescriptor) => boolean;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AccessLevels, MetadataDataDomains, DcmtTypeListCacheService, SystemMIDsAsNumber, MetadataDataTypes, QueryDescriptor, QueryFunctions, SelectItem, SelectItemVisibilities, FromItem, LayoutModes, QueryOperators, SavedQueryDescriptor, SearchEngine, WhereItem, OrderByItem, SDK_Globals, AppModules, SystemTIDs, WorkItemMetadataNames, PlatformObjectValidator } from '@topconsultnpm/sdk-ts';
|
|
1
|
+
import { AccessLevels, MetadataDataDomains, DcmtTypeListCacheService, SystemMIDsAsNumber, MetadataDataTypes, QueryDescriptor, QueryFunctions, SelectItem, SelectItemVisibilities, FromItem, LayoutModes, QueryOperators, SavedQueryDescriptor, SearchEngine, WhereItem, OrderByItem, SDK_Globals, AppModules, SystemTIDs, WorkItemMetadataNames, PlatformObjectValidator, MetadataSpecials } from '@topconsultnpm/sdk-ts';
|
|
2
2
|
import { DateDisplayTypes, Globalization } from './Globalization';
|
|
3
3
|
import { ChronologyMIDs, DraftsMIDs, MetadataValueDescriptorEx } from '../ts';
|
|
4
4
|
import { SDKUI_Localizator } from './SDKUI_Localizator';
|
|
@@ -265,6 +265,44 @@ export const getSysAllDcmtsSQD = async (tid, easyOr) => {
|
|
|
265
265
|
sqd.qd = await getQD(tid, easyOr, SDKUI_Globals.userSettings.searchSettings?.maxDcmtsToBeReturned ?? 1000);
|
|
266
266
|
return sqd;
|
|
267
267
|
};
|
|
268
|
+
/** MID dei metadati con tracciatura "Mostra file" del tipo documento */
|
|
269
|
+
export const getTraceShowFileMids = (dtd) => dtd?.metadata?.filter(md => md.special === MetadataSpecials.Trace_ShowFile && md.id !== undefined).map(md => md.id) ?? [];
|
|
270
|
+
/**
|
|
271
|
+
* Legge solo i metadati indicati del documento con una ricerca mirata.
|
|
272
|
+
* Se la ricerca fallisce o non li restituisce tutti (es. permessi), ripiega sulla GetMetadata completa.
|
|
273
|
+
*/
|
|
274
|
+
export const getDcmtMetadataValuesAsync = async (tid, did, mids) => {
|
|
275
|
+
const searchEngine = SDK_Globals.tmSession?.NewSearchEngine();
|
|
276
|
+
try {
|
|
277
|
+
let qd = SearchEngine.NewQueryDescriptor();
|
|
278
|
+
if (qd.from) {
|
|
279
|
+
qd.from.tid = tid;
|
|
280
|
+
qd.select = mids.map(mid => {
|
|
281
|
+
let si = new SelectItem();
|
|
282
|
+
si.tid = tid;
|
|
283
|
+
si.mid = mid;
|
|
284
|
+
si.visibility = SelectItemVisibilities.Visible;
|
|
285
|
+
return si;
|
|
286
|
+
});
|
|
287
|
+
let wiDID = new WhereItem();
|
|
288
|
+
wiDID.tid = tid;
|
|
289
|
+
wiDID.mid = SystemMIDsAsNumber.DID;
|
|
290
|
+
wiDID.operator = QueryOperators.Equal;
|
|
291
|
+
wiDID.value1 = did.toString();
|
|
292
|
+
wiDID.or = false;
|
|
293
|
+
wiDID.leftBrackets = '(';
|
|
294
|
+
wiDID.rightBrackets = ')';
|
|
295
|
+
qd.where = [wiDID];
|
|
296
|
+
const result = await searchEngine?.SearchByIDAsync(qd);
|
|
297
|
+
if (result?.dtdResult?.rows?.[0] && mids.every(mid => result.selectMIDs?.includes(mid)))
|
|
298
|
+
return result;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
catch (e) {
|
|
302
|
+
console.warn('Ricerca mirata dei metadati non riuscita, uso GetMetadata:', e);
|
|
303
|
+
}
|
|
304
|
+
return await searchEngine?.GetMetadataAsync(tid, did, true);
|
|
305
|
+
};
|
|
268
306
|
export const searchResultToMetadataValues = (tid, dtd, rows, mids, metadata, layoutMode, isReadOnlyOrigin = false) => {
|
|
269
307
|
if (!metadata || metadata.length === 0) {
|
|
270
308
|
return [];
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { useCallback, useEffect, useState } from 'react';
|
|
2
|
-
import { SDK_Globals } from '@topconsultnpm/sdk-ts';
|
|
2
|
+
import { CF_WorkItemCategories, SDK_Globals } from '@topconsultnpm/sdk-ts';
|
|
3
3
|
import { CaseFlowService } from '../services/caseflow/CaseFlowService';
|
|
4
|
-
import { getWorkItemTargetDoc,
|
|
4
|
+
import { getWorkItemTargetDoc, isSignatureWorkItem } from '../services/caseflow/caseFlowWorkItemUtils';
|
|
5
|
+
import { isFinalActionSync } from '../services/caseflow/caseFlowNameCache';
|
|
5
6
|
const CASEFLOW_APPROVE_CHANGED_EVENT = 'onCaseFlowApproveChange';
|
|
6
7
|
let cache = [];
|
|
7
8
|
let inFlight;
|
|
@@ -16,10 +17,27 @@ const notifyChanged = () => {
|
|
|
16
17
|
return;
|
|
17
18
|
window.dispatchEvent(new CustomEvent(CASEFLOW_APPROVE_CHANGED_EVENT));
|
|
18
19
|
};
|
|
20
|
+
/**
|
|
21
|
+
* Categorie che si completano DAL DOCUMENTO: firmarlo, approvarlo, prenderne
|
|
22
|
+
* visione. Le altre si completano nella pratica, perché il Toppy del form offre
|
|
23
|
+
* solo Approva/Rifiuta e non saprebbe fare il resto:
|
|
24
|
+
* - Caricamento manuale (Upload): il commento è obbligatorio (TMC-2822);
|
|
25
|
+
* - Generica / caricamento automatico: si chiude da sola quando il documento
|
|
26
|
+
* viene agganciato;
|
|
27
|
+
* - Completamento dati: vanno inseriti i valori dei metadati;
|
|
28
|
+
* - Verifica bloccante: sblocca o interrompe la pratica;
|
|
29
|
+
* - Richiesta informazioni: ha una risposta, non un esito.
|
|
30
|
+
*/
|
|
31
|
+
const DOCUMENT_CATEGORIES = new Set([
|
|
32
|
+
CF_WorkItemCategories.Approval,
|
|
33
|
+
CF_WorkItemCategories.Signature,
|
|
34
|
+
CF_WorkItemCategories.Acknowledgment,
|
|
35
|
+
]);
|
|
19
36
|
/**
|
|
20
37
|
* Ricarica la cache: i workitem pendenti dell'utente, risolti sul documento su
|
|
21
|
-
* cui lavorano.
|
|
22
|
-
*
|
|
38
|
+
* cui lavorano. Restano fuori le categorie che non si completano dal documento
|
|
39
|
+
* (vedi DOCUMENT_CATEGORIES), le azioni che chiudono la pratica e i workitem
|
|
40
|
+
* senza documento.
|
|
23
41
|
*/
|
|
24
42
|
const reload = async () => {
|
|
25
43
|
const userId = SDK_Globals.tmSession?.SessionDescr?.userID;
|
|
@@ -30,8 +48,7 @@ const reload = async () => {
|
|
|
30
48
|
const groups = await CaseFlowService.getMyPendingWorkItems(userId);
|
|
31
49
|
const resolved = [];
|
|
32
50
|
for (const { caseflow, workItems } of groups) {
|
|
33
|
-
|
|
34
|
-
const relevant = workItems.filter(wi => !isMoreInfoWorkItem(wi));
|
|
51
|
+
const relevant = workItems.filter(wi => DOCUMENT_CATEGORIES.has(wi.workItemCategory));
|
|
35
52
|
if (relevant.length === 0)
|
|
36
53
|
continue;
|
|
37
54
|
// Il TID dell'azione è autorato sul TEMPLATE e non materializzato
|
|
@@ -47,6 +64,14 @@ const reload = async () => {
|
|
|
47
64
|
instance = (await CaseFlowService.getCaseflow(instance.id, instance.cftid)) ?? instance;
|
|
48
65
|
}
|
|
49
66
|
for (const wi of relevant) {
|
|
67
|
+
// Un'azione che chiude la pratica richiede il motivo, che il Toppy del
|
|
68
|
+
// documento non chiede: si completa nella pratica. Il template è già
|
|
69
|
+
// risolto qui sopra, quindi `isFinal` è noto.
|
|
70
|
+
// La Firma resta: firmare si può solo da qui (l'ospite non ha altra
|
|
71
|
+
// strada). Fallirà il solo completamento automatico, che l'utente fa
|
|
72
|
+
// poi nella pratica scrivendo il motivo, con la firma già apposta.
|
|
73
|
+
if (!isSignatureWorkItem(wi) && isFinalActionSync(caseflow.cftid, wi.actionID))
|
|
74
|
+
continue;
|
|
50
75
|
const target = getWorkItemTargetDoc(instance, wi);
|
|
51
76
|
if (!target)
|
|
52
77
|
continue;
|
|
@@ -30,3 +30,8 @@ export declare function primeActionNames(template?: CaseFlowTemplateDescriptor |
|
|
|
30
30
|
* l'azione non lavora su un documento (o il template non è ancora risolto).
|
|
31
31
|
*/
|
|
32
32
|
export declare function getActionTidSync(cftid?: number, actionID?: number): number | undefined;
|
|
33
|
+
/**
|
|
34
|
+
* true se l'azione del template chiude la pratica (`isFinal`). Con il template
|
|
35
|
+
* non ancora risolto ritorna false.
|
|
36
|
+
*/
|
|
37
|
+
export declare function isFinalActionSync(cftid?: number, actionID?: number): boolean;
|
|
@@ -95,6 +95,11 @@ export function primeActionNames(template) {
|
|
|
95
95
|
actionNameCache.set(actionKey(cftid, a.id), a.name ?? '');
|
|
96
96
|
if (a.actionTID != null && a.actionTID > 0)
|
|
97
97
|
actionTidCache.set(actionKey(cftid, a.id), a.actionTID);
|
|
98
|
+
// Il template può essere stato modificato: la chiave va anche tolta.
|
|
99
|
+
if (a.isFinal)
|
|
100
|
+
finalActionKeys.add(actionKey(cftid, a.id));
|
|
101
|
+
else
|
|
102
|
+
finalActionKeys.delete(actionKey(cftid, a.id));
|
|
98
103
|
}
|
|
99
104
|
}
|
|
100
105
|
// ---- TID documento per azione (per template) --------------------------------
|
|
@@ -114,3 +119,17 @@ export function getActionTidSync(cftid, actionID) {
|
|
|
114
119
|
return undefined;
|
|
115
120
|
return actionTidCache.get(actionKey(cftid, actionID));
|
|
116
121
|
}
|
|
122
|
+
// ---- Azioni che chiudono la pratica (per template) ---------------------------
|
|
123
|
+
//
|
|
124
|
+
// Anche `isFinal` vive solo SUL TEMPLATE: sull'azione d'istanza arriva sempre
|
|
125
|
+
// false. Popolata da {@link primeActionNames} come le cache qui sopra.
|
|
126
|
+
const finalActionKeys = new Set();
|
|
127
|
+
/**
|
|
128
|
+
* true se l'azione del template chiude la pratica (`isFinal`). Con il template
|
|
129
|
+
* non ancora risolto ritorna false.
|
|
130
|
+
*/
|
|
131
|
+
export function isFinalActionSync(cftid, actionID) {
|
|
132
|
+
if (cftid == null || actionID == null)
|
|
133
|
+
return false;
|
|
134
|
+
return finalActionKeys.has(actionKey(cftid, actionID));
|
|
135
|
+
}
|