@topconsultnpm/sdkui-react 6.22.0-dev2.5 → 6.22.0-dev2.50
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/NewComponents/ContextMenu/TMContextMenu.js +1 -1
- package/lib/components/NewComponents/FloatingMenuBar/TMFloatingMenuBar.js +1 -1
- package/lib/components/base/TMDataGrid.d.ts +2 -0
- package/lib/components/base/TMDataGrid.js +260 -8
- package/lib/components/base/TMEditorBase.d.ts +2 -0
- package/lib/components/base/TMFileManager.js +5 -3
- package/lib/components/base/TMFileManagerDataGridView.js +11 -2
- package/lib/components/base/TMFileManagerThumbnailItems.js +19 -9
- package/lib/components/base/TMFileManagerUtils.d.ts +2 -0
- package/lib/components/base/TMFileManagerUtils.js +37 -1
- package/lib/components/base/TMModal.d.ts +11 -0
- package/lib/components/base/TMModal.js +47 -13
- package/lib/components/base/TMPanel.d.ts +6 -0
- package/lib/components/base/TMPanel.js +221 -108
- package/lib/components/base/TMPopUp.js +3 -0
- package/lib/components/base/TMTooltip.d.ts +2 -1
- package/lib/components/base/TMTooltip.js +24 -8
- package/lib/components/base/TMTreeView.js +108 -67
- package/lib/components/choosers/TMDcmtTypeChooser.js +4 -3
- package/lib/components/choosers/TMDistinctValues.d.ts +9 -7
- package/lib/components/choosers/TMDistinctValues.js +149 -142
- package/lib/components/choosers/TMMetadataChooser.js +1 -1
- package/lib/components/choosers/TMQuickSearchInfo.d.ts +12 -0
- package/lib/components/choosers/TMQuickSearchInfo.js +279 -0
- package/lib/components/choosers/TMQuickSearchSettingsForm.d.ts +16 -0
- package/lib/components/choosers/TMQuickSearchSettingsForm.js +94 -0
- package/lib/components/choosers/TMSelectedValuesSummary.d.ts +13 -0
- package/lib/components/choosers/TMSelectedValuesSummary.js +91 -0
- package/lib/components/editors/TMDropDown.d.ts +3 -0
- package/lib/components/editors/TMDropDown.js +197 -5
- package/lib/components/editors/TMMetadataEditor.d.ts +5 -1
- package/lib/components/editors/TMMetadataEditor.js +8 -3
- package/lib/components/editors/TMTextBox.js +2 -2
- package/lib/components/features/archive/TMArchive.js +17 -3
- package/lib/components/features/documents/TMBatchUpdateForm.js +19 -5
- package/lib/components/features/documents/TMDcmtBlog.d.ts +3 -0
- package/lib/components/features/documents/TMDcmtBlog.js +4 -4
- package/lib/components/features/documents/TMDcmtForm.d.ts +7 -0
- package/lib/components/features/documents/TMDcmtForm.js +151 -46
- package/lib/components/features/documents/TMDcmtFormActionButtons.d.ts +11 -0
- package/lib/components/features/documents/TMDcmtFormActionButtons.js +74 -7
- package/lib/components/features/documents/TMDcmtIcon.js +5 -3
- package/lib/components/features/documents/TMDcmtPreview.js +10 -6
- package/lib/components/features/documents/TMMasterDetailDcmts.js +95 -33
- package/lib/components/features/documents/TMMasterInfoFields.d.ts +19 -0
- package/lib/components/features/documents/TMMasterInfoFields.js +186 -0
- package/lib/components/features/documents/TMMergeToPdfForm.d.ts +1 -2
- package/lib/components/features/documents/TMMergeToPdfForm.js +30 -5
- package/lib/components/features/documents/TMMultiMasterDetailDcmtsForm.d.ts +45 -0
- package/lib/components/features/documents/TMMultiMasterDetailDcmtsForm.js +323 -0
- package/lib/components/features/documents/TMMultiMasterDetailDcmtsUtils.d.ts +370 -0
- package/lib/components/features/documents/TMMultiMasterDetailDcmtsUtils.js +283 -0
- package/lib/components/features/documents/TMRelationViewer.d.ts +14 -1
- package/lib/components/features/documents/TMRelationViewer.js +69 -20
- package/lib/components/features/search/TMSearch.js +77 -11
- package/lib/components/features/search/TMSearchQueryEditor.js +5 -3
- package/lib/components/features/search/TMSearchQueryPanel.d.ts +4 -0
- package/lib/components/features/search/TMSearchQueryPanel.js +141 -67
- package/lib/components/features/search/TMSearchResult.d.ts +16 -0
- package/lib/components/features/search/TMSearchResult.js +432 -109
- package/lib/components/features/search/TMTreeSelector.js +166 -130
- package/lib/components/features/workflow/TMWorkflowPopup.d.ts +10 -0
- package/lib/components/features/workflow/TMWorkflowPopup.js +8 -4
- package/lib/components/grids/TMBlogAttachments.js +13 -2
- package/lib/components/grids/TMBlogsPost.d.ts +2 -0
- package/lib/components/grids/TMBlogsPost.js +26 -3
- package/lib/components/grids/TMBlogsPostUtils.d.ts +1 -0
- package/lib/components/grids/TMBlogsPostUtils.js +14 -3
- package/lib/components/layout/panelManager/TMPanelManagerContainer.d.ts +1 -0
- package/lib/components/layout/panelManager/TMPanelManagerContainer.js +24 -14
- package/lib/components/layout/panelManager/TMPanelManagerContext.js +68 -93
- package/lib/components/layout/panelManager/TMPanelWrapper.js +2 -2
- package/lib/components/layout/panelManager/types.d.ts +3 -0
- package/lib/components/layout/panelManager/utils.js +13 -11
- package/lib/components/sidebar/TMHeader.js +30 -20
- package/lib/components/viewers/TMMidViewer.js +4 -1
- package/lib/components/viewers/TMTidViewer.js +83 -22
- package/lib/devextreme-license.d.ts +1 -0
- package/lib/devextreme-license.js +3 -0
- package/lib/helper/SDKUI_Globals.d.ts +110 -0
- package/lib/helper/SDKUI_Globals.js +151 -0
- package/lib/helper/SDKUI_Localizator.d.ts +42 -0
- package/lib/helper/SDKUI_Localizator.js +420 -0
- package/lib/helper/TMAppUpdatedModal.d.ts +1 -0
- package/lib/helper/TMAppUpdatedModal.js +134 -0
- package/lib/helper/TMIcons.d.ts +1 -0
- package/lib/helper/TMIcons.js +3 -0
- package/lib/helper/TMUtils.d.ts +7 -0
- package/lib/helper/TMUtils.js +15 -1
- package/lib/helper/dataGridSearchHelper.d.ts +28 -0
- package/lib/helper/dataGridSearchHelper.js +51 -0
- package/lib/helper/dcmtsHelper.d.ts +20 -0
- package/lib/helper/dcmtsHelper.js +58 -1
- package/lib/helper/helpers.d.ts +11 -0
- package/lib/helper/helpers.js +25 -1
- package/lib/helper/index.d.ts +2 -0
- package/lib/helper/index.js +2 -0
- package/lib/helper/queryHelper.d.ts +6 -1
- package/lib/helper/queryHelper.js +8 -3
- package/lib/hooks/tmDistinctValuesGridHelper.d.ts +16 -0
- package/lib/hooks/tmDistinctValuesGridHelper.js +31 -0
- package/lib/hooks/useArchiveListForm.d.ts +39 -0
- package/lib/hooks/useArchiveListForm.js +46 -0
- package/lib/hooks/useCaseFlowApprove.d.ts +56 -0
- package/lib/hooks/useCaseFlowApprove.js +157 -0
- package/lib/hooks/useDataUserIdItem.d.ts +1 -0
- package/lib/hooks/useDataUserIdItem.js +1 -0
- package/lib/hooks/useDocumentOperations.d.ts +4 -0
- package/lib/hooks/useDocumentOperations.js +50 -10
- package/lib/hooks/useMultiMasterDetailDcmts.d.ts +113 -0
- package/lib/hooks/useMultiMasterDetailDcmts.js +760 -0
- package/lib/hooks/useRelatedDocuments.d.ts +1 -0
- package/lib/hooks/useRelatedDocuments.js +22 -27
- package/lib/hooks/useShowDossiersV5.d.ts +12 -0
- package/lib/hooks/useShowDossiersV5.js +37 -0
- package/lib/hooks/useTMDistinctValuesMetadataDisplay.d.ts +18 -0
- package/lib/hooks/useTMDistinctValuesMetadataDisplay.js +103 -0
- package/lib/hooks/useTMDistinctValuesQuickSearch.d.ts +49 -0
- package/lib/hooks/useTMDistinctValuesQuickSearch.js +307 -0
- package/lib/hooks/useTMDistinctValuesSelection.d.ts +42 -0
- package/lib/hooks/useTMDistinctValuesSelection.js +103 -0
- package/lib/hooks/useTMDistinctValuesSource.d.ts +29 -0
- package/lib/hooks/useTMDistinctValuesSource.js +105 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.js +5 -2
- package/lib/services/caseflow/CaseFlowService.d.ts +236 -0
- package/lib/services/caseflow/CaseFlowService.js +693 -0
- package/lib/services/caseflow/CaseFlowTemplateCacheService.d.ts +28 -0
- package/lib/services/caseflow/CaseFlowTemplateCacheService.js +121 -0
- package/lib/services/caseflow/caseFlowNameCache.d.ts +32 -0
- package/lib/services/caseflow/caseFlowNameCache.js +116 -0
- package/lib/services/caseflow/caseFlowWorkItemUtils.d.ts +61 -0
- package/lib/services/caseflow/caseFlowWorkItemUtils.js +113 -0
- package/lib/services/index.d.ts +4 -0
- package/lib/services/index.js +4 -0
- package/lib/services/platform_services.d.ts +1 -1
- package/package.json +9 -5
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { useCallback, useMemo } from 'react';
|
|
2
|
+
import { ButtonNames, TMMessageBoxManager } from '../components';
|
|
3
|
+
/** Isola la logica della modalità "aggiungi a elenco": valori di riferimento, submit e chiusura del form. */
|
|
4
|
+
export const useArchiveListForm = ({ mode, editingRowValues, formDataOrig, formDataRef, dcmtFileRef, tid, isModal, id, clearForm, }) => {
|
|
5
|
+
const enabled = !!mode;
|
|
6
|
+
const isEditingRow = !!mode?.isEditingRow;
|
|
7
|
+
// Valori con cui si confronta il form per capire cosa è cambiato (flag "modificato" ed evidenza gialla).
|
|
8
|
+
// Modificando una riga si parte dai suoi valori, così i campi pre-compilati non risultano subito modificati.
|
|
9
|
+
const referenceValues = useMemo(() => {
|
|
10
|
+
if (!isEditingRow || !editingRowValues || editingRowValues.length === 0)
|
|
11
|
+
return formDataOrig;
|
|
12
|
+
return formDataOrig.map(md => {
|
|
13
|
+
const rowValue = editingRowValues.find(rv => rv.mid === md.mid);
|
|
14
|
+
return rowValue ? { ...md, value: rowValue.value } : md;
|
|
15
|
+
});
|
|
16
|
+
}, [isEditingRow, editingRowValues, formDataOrig]);
|
|
17
|
+
// Restituisce metadati e file al chiamante, poi svuota il form.
|
|
18
|
+
const submit = useCallback(() => {
|
|
19
|
+
if (!mode)
|
|
20
|
+
return;
|
|
21
|
+
const values = formDataRef.current.filter(md => md.mid !== undefined && md.mid > 99);
|
|
22
|
+
mode.onUpsertRow(values, dcmtFileRef.current ?? undefined, tid);
|
|
23
|
+
clearForm();
|
|
24
|
+
}, [mode, formDataRef, dcmtFileRef, tid, clearForm]);
|
|
25
|
+
// Gestisce la chiusura del form
|
|
26
|
+
const requestClose = useCallback((isModified, onClose) => {
|
|
27
|
+
if (!mode)
|
|
28
|
+
return false;
|
|
29
|
+
if (!isModified) {
|
|
30
|
+
onClose?.();
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
TMMessageBoxManager.show({
|
|
34
|
+
parentId: isModal ? "TMDcmtFormShowConfirmForClose-" + id : undefined,
|
|
35
|
+
message: "Chiudendo, le modifiche andranno perse. Proseguire?",
|
|
36
|
+
buttons: [ButtonNames.YES, ButtonNames.NO],
|
|
37
|
+
onButtonClick: (e) => {
|
|
38
|
+
// Sì: scarta le modifiche e chiude senza aggiungere all'elenco. No: resta sul form.
|
|
39
|
+
if (e == ButtonNames.YES)
|
|
40
|
+
onClose?.();
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
return true;
|
|
44
|
+
}, [mode, isModal, id]);
|
|
45
|
+
return { enabled, isEditingRow, referenceValues, submit, requestClose };
|
|
46
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { CaseFlowInstanceDescriptor, CaseFlowWorkItem } from '@topconsultnpm/sdk-ts';
|
|
2
|
+
/**
|
|
3
|
+
* Attività (workitem) delle PRATICHE assegnate all'utente, con il documento su
|
|
4
|
+
* cui lavorano già risolto.
|
|
5
|
+
*
|
|
6
|
+
* Gemello di `useWorkflowApprove` per il modulo CaseFlow: i dati stanno in una
|
|
7
|
+
* cache di modulo e le istanze del hook si sincronizzano con un evento, così il
|
|
8
|
+
* form del documento — da qualunque punto venga aperto — sa che su quel TID/DID
|
|
9
|
+
* c'è una firma da fare o un'approvazione da dare, senza che il chiamante debba
|
|
10
|
+
* passargli nulla.
|
|
11
|
+
*/
|
|
12
|
+
/** Workitem di pratica già risolto sul documento cui si riferisce. */
|
|
13
|
+
export interface CaseFlowDcmtWorkItem {
|
|
14
|
+
caseflow: CaseFlowInstanceDescriptor;
|
|
15
|
+
workItem: CaseFlowWorkItem;
|
|
16
|
+
tid: number;
|
|
17
|
+
did: number;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Ricarica i workitem di pratica dell'utente. Con `force` ignora la finestra
|
|
21
|
+
* anti-raffica (da usare dopo un'operazione che li ha modificati).
|
|
22
|
+
*/
|
|
23
|
+
export declare const refreshCaseFlowApproveData: (force?: boolean) => Promise<void>;
|
|
24
|
+
/**
|
|
25
|
+
* Workitem di pratica pendenti su quel documento (lettura sincrona dalla cache).
|
|
26
|
+
*
|
|
27
|
+
* TID/DID vanno NORMALIZZATI: pur essendo tipati `number`, arrivano come stringhe
|
|
28
|
+
* quando il documento è aperto da una griglia (righe di datagrid) — per lo stesso
|
|
29
|
+
* motivo il resto della libreria fa `Number(TID)`/`Number(DID)` in ogni confronto.
|
|
30
|
+
* Senza normalizzazione il confronto stretto falliva, e l'attività risultava
|
|
31
|
+
* assente aprendo il documento dalla ricerca mentre compariva dal widget "Per te".
|
|
32
|
+
*/
|
|
33
|
+
export declare const getCaseFlowWorkItemsByDcmt: (tid?: number | string, did?: number | string) => CaseFlowDcmtWorkItem[];
|
|
34
|
+
/** Svuota la cache (logout / cambio archivio). */
|
|
35
|
+
export declare const clearCaseFlowApproveData: () => void;
|
|
36
|
+
/** Completa il workitem di pratica e ricarica la cache. */
|
|
37
|
+
export declare const completeCaseFlowWorkItem: (item: CaseFlowDcmtWorkItem, comment?: string) => Promise<void>;
|
|
38
|
+
/** Rifiuta il workitem di pratica (motivo obbligatorio) e ricarica la cache. */
|
|
39
|
+
export declare const rejectCaseFlowWorkItem: (item: CaseFlowDcmtWorkItem, reason: string) => Promise<void>;
|
|
40
|
+
/**
|
|
41
|
+
* Completa l'attività di FIRMA di una pratica sul documento indicato, se esiste.
|
|
42
|
+
* La chiama il viewer di firma quando la firma è riuscita: è il gemello di quanto
|
|
43
|
+
* già avviene per i workitem del workflow legacy.
|
|
44
|
+
* @returns true se un'attività è stata completata.
|
|
45
|
+
*/
|
|
46
|
+
export declare const completeCaseFlowSignatureForDcmt: (tid: number | string, did: number | string, comment?: string) => Promise<boolean>;
|
|
47
|
+
/**
|
|
48
|
+
* Attività di pratica sul documento indicato. Senza sessione o senza attività
|
|
49
|
+
* l'elenco è vuoto e nulla cambia nella UI.
|
|
50
|
+
*/
|
|
51
|
+
export declare const useCaseFlowApprove: (tid?: number | string, did?: number | string) => {
|
|
52
|
+
caseFlowWorkItems: CaseFlowDcmtWorkItem[];
|
|
53
|
+
refreshCaseFlowApprove: (force?: boolean) => Promise<void>;
|
|
54
|
+
completeCaseFlowWorkItem: (item: CaseFlowDcmtWorkItem, comment?: string) => Promise<void>;
|
|
55
|
+
rejectCaseFlowWorkItem: (item: CaseFlowDcmtWorkItem, reason: string) => Promise<void>;
|
|
56
|
+
};
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { useCallback, useEffect, useState } from 'react';
|
|
2
|
+
import { SDK_Globals } from '@topconsultnpm/sdk-ts';
|
|
3
|
+
import { CaseFlowService } from '../services/caseflow/CaseFlowService';
|
|
4
|
+
import { getWorkItemTargetDoc, isMoreInfoWorkItem, isSignatureWorkItem } from '../services/caseflow/caseFlowWorkItemUtils';
|
|
5
|
+
const CASEFLOW_APPROVE_CHANGED_EVENT = 'onCaseFlowApproveChange';
|
|
6
|
+
let cache = [];
|
|
7
|
+
let inFlight;
|
|
8
|
+
let lastLoadedAt = 0;
|
|
9
|
+
/**
|
|
10
|
+
* Finestra minima fra due ricariche: il form del documento chiede un refresh a
|
|
11
|
+
* ogni apertura e la lista è una scansione delle istanze, non una query puntuale.
|
|
12
|
+
*/
|
|
13
|
+
const MIN_RELOAD_INTERVAL_MS = 15000;
|
|
14
|
+
const notifyChanged = () => {
|
|
15
|
+
if (typeof window === 'undefined')
|
|
16
|
+
return;
|
|
17
|
+
window.dispatchEvent(new CustomEvent(CASEFLOW_APPROVE_CHANGED_EVENT));
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Ricarica la cache: i workitem pendenti dell'utente, risolti sul documento su
|
|
21
|
+
* cui lavorano. Le richieste di informazioni sono escluse (si rispondono nella
|
|
22
|
+
* pratica, non sul documento) come i workitem senza documento.
|
|
23
|
+
*/
|
|
24
|
+
const reload = async () => {
|
|
25
|
+
const userId = SDK_Globals.tmSession?.SessionDescr?.userID;
|
|
26
|
+
if (userId == null) {
|
|
27
|
+
cache = [];
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const groups = await CaseFlowService.getMyPendingWorkItems(userId);
|
|
31
|
+
const resolved = [];
|
|
32
|
+
for (const { caseflow, workItems } of groups) {
|
|
33
|
+
// Le richieste di informazioni si rispondono nella pratica, non sul documento.
|
|
34
|
+
const relevant = workItems.filter(wi => !isMoreInfoWorkItem(wi));
|
|
35
|
+
if (relevant.length === 0)
|
|
36
|
+
continue;
|
|
37
|
+
// Il TID dell'azione è autorato sul TEMPLATE e non materializzato
|
|
38
|
+
// sull'istanza: senza template risolto il documento non è calcolabile.
|
|
39
|
+
if (caseflow.cftid != null) {
|
|
40
|
+
await CaseFlowService.getTemplate(caseflow.cftid);
|
|
41
|
+
}
|
|
42
|
+
// I DOCUMENTI AGGANCIATI non arrivano dalla RetrieveAll (che porta solo i
|
|
43
|
+
// dati delle card): serve la Retrieve completa, altrimenti `dcmts` è vuoto
|
|
44
|
+
// e nessun workitem risulterebbe associato a un documento.
|
|
45
|
+
let instance = caseflow;
|
|
46
|
+
if ((instance.dcmts?.length ?? 0) === 0 && instance.id != null) {
|
|
47
|
+
instance = (await CaseFlowService.getCaseflow(instance.id, instance.cftid)) ?? instance;
|
|
48
|
+
}
|
|
49
|
+
for (const wi of relevant) {
|
|
50
|
+
const target = getWorkItemTargetDoc(instance, wi);
|
|
51
|
+
if (!target)
|
|
52
|
+
continue;
|
|
53
|
+
resolved.push({ caseflow: instance, workItem: wi, tid: target.tid, did: target.did });
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
cache = resolved;
|
|
57
|
+
lastLoadedAt = Date.now();
|
|
58
|
+
// Diagnostica del bring-up: se il Toppy non compare, qui si vede a che punto
|
|
59
|
+
// la catena si interrompe (nessun workitem / nessun documento risolto).
|
|
60
|
+
// Rimuovibile una volta stabilizzato il flusso.
|
|
61
|
+
console.debug('[CaseFlow] attività su documenti:', {
|
|
62
|
+
istanzeConPendenti: groups.length,
|
|
63
|
+
workItemPendenti: groups.reduce((n, g) => n + g.workItems.length, 0),
|
|
64
|
+
risolteSuDocumento: resolved.length,
|
|
65
|
+
documenti: resolved.map(r => `${r.tid}/${r.did}`),
|
|
66
|
+
});
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* Ricarica i workitem di pratica dell'utente. Con `force` ignora la finestra
|
|
70
|
+
* anti-raffica (da usare dopo un'operazione che li ha modificati).
|
|
71
|
+
*/
|
|
72
|
+
export const refreshCaseFlowApproveData = async (force = false) => {
|
|
73
|
+
if (inFlight)
|
|
74
|
+
return inFlight;
|
|
75
|
+
if (!force && lastLoadedAt > 0 && Date.now() - lastLoadedAt < MIN_RELOAD_INTERVAL_MS)
|
|
76
|
+
return;
|
|
77
|
+
inFlight = reload()
|
|
78
|
+
.catch(error => { console.error('Errore nel caricare le attività di pratica sui documenti', error); })
|
|
79
|
+
.finally(() => { inFlight = undefined; notifyChanged(); });
|
|
80
|
+
return inFlight;
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* Workitem di pratica pendenti su quel documento (lettura sincrona dalla cache).
|
|
84
|
+
*
|
|
85
|
+
* TID/DID vanno NORMALIZZATI: pur essendo tipati `number`, arrivano come stringhe
|
|
86
|
+
* quando il documento è aperto da una griglia (righe di datagrid) — per lo stesso
|
|
87
|
+
* motivo il resto della libreria fa `Number(TID)`/`Number(DID)` in ogni confronto.
|
|
88
|
+
* Senza normalizzazione il confronto stretto falliva, e l'attività risultava
|
|
89
|
+
* assente aprendo il documento dalla ricerca mentre compariva dal widget "Per te".
|
|
90
|
+
*/
|
|
91
|
+
export const getCaseFlowWorkItemsByDcmt = (tid, did) => {
|
|
92
|
+
const t = Number(tid);
|
|
93
|
+
const d = Number(did);
|
|
94
|
+
if (!Number.isFinite(t) || !Number.isFinite(d))
|
|
95
|
+
return [];
|
|
96
|
+
return cache.filter(r => Number(r.tid) === t && Number(r.did) === d);
|
|
97
|
+
};
|
|
98
|
+
/** Svuota la cache (logout / cambio archivio). */
|
|
99
|
+
export const clearCaseFlowApproveData = () => {
|
|
100
|
+
cache = [];
|
|
101
|
+
lastLoadedAt = 0;
|
|
102
|
+
notifyChanged();
|
|
103
|
+
};
|
|
104
|
+
/** Completa il workitem di pratica e ricarica la cache. */
|
|
105
|
+
export const completeCaseFlowWorkItem = async (item, comment) => {
|
|
106
|
+
if (item.caseflow.id == null || item.workItem.id == null)
|
|
107
|
+
return;
|
|
108
|
+
await CaseFlowService.completeWorkItem(item.caseflow.id, item.workItem.id, comment?.trim() || undefined);
|
|
109
|
+
await refreshCaseFlowApproveData(true);
|
|
110
|
+
};
|
|
111
|
+
/** Rifiuta il workitem di pratica (motivo obbligatorio) e ricarica la cache. */
|
|
112
|
+
export const rejectCaseFlowWorkItem = async (item, reason) => {
|
|
113
|
+
if (item.caseflow.id == null || item.workItem.id == null)
|
|
114
|
+
return;
|
|
115
|
+
await CaseFlowService.rejectWorkItem(item.caseflow.id, item.workItem.id, reason);
|
|
116
|
+
await refreshCaseFlowApproveData(true);
|
|
117
|
+
};
|
|
118
|
+
/**
|
|
119
|
+
* Completa l'attività di FIRMA di una pratica sul documento indicato, se esiste.
|
|
120
|
+
* La chiama il viewer di firma quando la firma è riuscita: è il gemello di quanto
|
|
121
|
+
* già avviene per i workitem del workflow legacy.
|
|
122
|
+
* @returns true se un'attività è stata completata.
|
|
123
|
+
*/
|
|
124
|
+
export const completeCaseFlowSignatureForDcmt = async (tid, did, comment) => {
|
|
125
|
+
const target = getCaseFlowWorkItemsByDcmt(tid, did).find(r => isSignatureWorkItem(r.workItem));
|
|
126
|
+
if (!target)
|
|
127
|
+
return false;
|
|
128
|
+
await completeCaseFlowWorkItem(target, comment);
|
|
129
|
+
return true;
|
|
130
|
+
};
|
|
131
|
+
/**
|
|
132
|
+
* Attività di pratica sul documento indicato. Senza sessione o senza attività
|
|
133
|
+
* l'elenco è vuoto e nulla cambia nella UI.
|
|
134
|
+
*/
|
|
135
|
+
export const useCaseFlowApprove = (tid, did) => {
|
|
136
|
+
const readItems = useCallback(() => getCaseFlowWorkItemsByDcmt(tid, did), [tid, did]);
|
|
137
|
+
const [caseFlowWorkItems, setCaseFlowWorkItems] = useState(readItems);
|
|
138
|
+
useEffect(() => { setCaseFlowWorkItems(readItems()); }, [readItems]);
|
|
139
|
+
useEffect(() => {
|
|
140
|
+
const handleChange = () => setCaseFlowWorkItems(readItems());
|
|
141
|
+
window.addEventListener(CASEFLOW_APPROVE_CHANGED_EVENT, handleChange);
|
|
142
|
+
return () => window.removeEventListener(CASEFLOW_APPROVE_CHANGED_EVENT, handleChange);
|
|
143
|
+
}, [readItems]);
|
|
144
|
+
// All'apertura di un documento la cache può essere vecchia (attività assegnate
|
|
145
|
+
// dopo l'ultimo caricamento) o non ancora popolata.
|
|
146
|
+
useEffect(() => {
|
|
147
|
+
if (tid == null || did == null)
|
|
148
|
+
return;
|
|
149
|
+
void refreshCaseFlowApproveData();
|
|
150
|
+
}, [tid, did]);
|
|
151
|
+
return {
|
|
152
|
+
caseFlowWorkItems,
|
|
153
|
+
refreshCaseFlowApprove: refreshCaseFlowApproveData,
|
|
154
|
+
completeCaseFlowWorkItem,
|
|
155
|
+
rejectCaseFlowWorkItem,
|
|
156
|
+
};
|
|
157
|
+
};
|
|
@@ -3,6 +3,7 @@ import { UserDescriptor } from '@topconsultnpm/sdk-ts';
|
|
|
3
3
|
export declare const useDataUserIdItem: () => {
|
|
4
4
|
loadUsersAsync: (userIDs: Set<number>) => Promise<void>;
|
|
5
5
|
getUserItem: (userId: number) => UserDescriptor | undefined;
|
|
6
|
+
getCompleteUserName: (domain: string | undefined, name: string | undefined) => string | undefined;
|
|
6
7
|
clearCache: () => void;
|
|
7
8
|
hasUser: (userId: number) => boolean;
|
|
8
9
|
usersCache: React.MutableRefObject<Map<number, UserDescriptor>>;
|
|
@@ -105,10 +105,13 @@ interface UseDocumentOperationsProps {
|
|
|
105
105
|
}
|
|
106
106
|
export interface UseDocumentOperationsResult {
|
|
107
107
|
operationItems: Array<TMContextMenuItemProps>;
|
|
108
|
+
selectedDcmtInfos: Array<DcmtInfo>;
|
|
108
109
|
renderFloatingBar: React.ReactNode;
|
|
109
110
|
renderDcmtOperations: React.ReactNode;
|
|
110
111
|
features: {
|
|
111
112
|
isOpenDcmtForm: boolean;
|
|
113
|
+
/** Il form del documento è aperto come popup sopra il contenuto, che resta visibile sotto */
|
|
114
|
+
isDcmtFormModal: boolean;
|
|
112
115
|
openFormHandler: (layoutMode: LayoutModes) => void;
|
|
113
116
|
dcmtFormLayoutMode: LayoutModes;
|
|
114
117
|
onDcmtFormOpenChange: (isOpen: boolean, layoutMode: LayoutModes) => void;
|
|
@@ -118,6 +121,7 @@ export interface UseDocumentOperationsResult {
|
|
|
118
121
|
closeDcmtFormHandler: () => void;
|
|
119
122
|
handleSignApprove: () => void;
|
|
120
123
|
showSearchTMDatagrid: boolean;
|
|
124
|
+
showDcmtTypesSelection: boolean;
|
|
121
125
|
showExportForm: boolean;
|
|
122
126
|
checkoutInfo: UseCheckInOutOperationsReturn;
|
|
123
127
|
relatedDocumentsInfo: UseRelatedDocumentsReturn;
|
|
@@ -21,10 +21,11 @@ import { useDcmtOperations } from "./useDcmtOperations";
|
|
|
21
21
|
import useFloatingBarPinnedItems from "./useFloatingBarPinnedItems";
|
|
22
22
|
import { useInputAttachmentsDialog, useInputCvtFormatDialog } from "./useInputDialog";
|
|
23
23
|
import { useRelatedDocuments } from "./useRelatedDocuments";
|
|
24
|
-
import { convertSearchResultDescriptorToFileItems, dcmtsFileCachePreview, getDcmtCicoStatus, getMoreInfoTasksForDocument, IconActivity, IconArchiveDetail, IconArchiveDoc, IconArchiveMaster, IconBatchUpdate, IconCheck, IconCheckFile, IconCheckIn, IconCircleInfo, IconCloseCircle, IconConvertFilePdf, IconCopy, IconCustom, IconDelete, IconDetailDcmts, IconDotsVerticalCircleOutline, IconDownload, IconEdit, IconExportTo, IconFileDots, IconHide, IconInfo, IconMenuCAArchive, IconMoveToFolder, IconPair, IconPin, IconPlatform, IconPreview, IconRelation, IconSearch, IconShare, IconSharedDcmt, IconShow, IconSignaturePencil, IconStar, IconSubstFile, IconUndo, IconUnpair, IconUserGroupOutline, isConvertibleToPdfExt, isPdfEditorAvailable, S4T_USER_REGISTRY_MASTER, SDKUI_Globals, SDKUI_Localizator, searchResultToMetadataValues, TMImageLibrary, IconCertificateBadge } from '../helper';
|
|
24
|
+
import { convertSearchResultDescriptorToFileItems, dcmtsFileCachePreview, getDcmtCicoStatus, getMoreInfoTasksForDocument, IconActivity, IconArchiveDetail, IconArchiveDoc, IconArchiveMaster, IconBatchUpdate, IconCheck, IconCheckFile, IconCheckIn, IconCircleInfo, IconCloseCircle, IconConvertFilePdf, IconCopy, IconCustom, IconDelete, IconDetailDcmts, IconDotsVerticalCircleOutline, IconDownload, IconEdit, IconExportTo, IconFileDots, IconHide, IconInfo, IconMenuCAArchive, IconMoveToFolder, IconPair, IconPin, IconPlatform, IconPreview, IconRelation, IconSearch, IconShare, IconSharedDcmt, IconShow, IconSignaturePencil, IconStar, IconSubstFile, IconUndo, IconUnpair, IconUserGroupOutline, isConvertibleToPdfExt, isPdfEditorAvailable, S4T_USER_REGISTRY_MASTER, SDKUI_Globals, SDKUI_Localizator, searchResultToMetadataValues, TMImageLibrary, IconCertificateBadge, IconArchiveMultipleDetailDocuments } from '../helper';
|
|
25
25
|
import { isXMLFileExt } from "../helper/dcmtsHelper";
|
|
26
26
|
import TMCopyToFolderForm from "../components/features/documents/TMCopyToFolderForm";
|
|
27
27
|
import TMMergeToPdfForm from "../components/features/documents/TMMergeToPdfForm";
|
|
28
|
+
import TMMultiMasterDetailDcmtsForm from "../components/features/documents/TMMultiMasterDetailDcmtsForm";
|
|
28
29
|
export const getSelectedDcmtsOrFocused = (selectedItems, focusedItem, fileFormat) => {
|
|
29
30
|
if (selectedItems.length <= 0 && !focusedItem)
|
|
30
31
|
return [];
|
|
@@ -116,7 +117,7 @@ export const useDocumentOperations = (props) => {
|
|
|
116
117
|
// Data
|
|
117
118
|
relatedDcmts, pairedSearchResults, manyToManyRelations, selectedManyToManyRelation, manyToManyChooserDataSource, relatedDcmtsChooserDataSource,
|
|
118
119
|
// Flags / State booleans
|
|
119
|
-
showRelatedDcmtsChooser, isOpenDetails, isOpenMaster, isOpenArchiveRelationForm, isPairingManyToMany, showManyToManyChooser, showPairSearchModal, currentTIDHasDetailRelations, currentTIDHasMasterRelations, canArchiveMasterRelation, canArchiveDetailRelation, hasManyToManyRelation, showPairDcmtsModal,
|
|
120
|
+
showRelatedDcmtsChooser, isOpenDetails, isOpenMaster, isOpenArchiveRelationForm, isPairingManyToMany, showManyToManyChooser, showPairSearchModal, currentTIDHasDetailRelations, currentTIDHasMasterRelations, canArchiveMasterRelation, canArchiveDetailRelation, hasManyToManyRelation, showPairDcmtsModal, backToPairSearchModal,
|
|
120
121
|
// Pair search modal state
|
|
121
122
|
pairSearchModalTargetTID, pairSearchModalParentTID, pairSearchModalParentDID, pairSearchModalRelation, pairSearchModalInputMids,
|
|
122
123
|
// Config
|
|
@@ -149,9 +150,16 @@ export const useDocumentOperations = (props) => {
|
|
|
149
150
|
const [showFloatingBar, setShowFloatingBar] = useState(allowFloatingBar);
|
|
150
151
|
const [isOpenDcmtForm, setIsOpenDcmtForm] = useState(false);
|
|
151
152
|
const [dcmtFormLayoutMode, setDcmtFormLayoutMode] = useState(LayoutModes.Update);
|
|
153
|
+
/**
|
|
154
|
+
* Il form del documento è a popup: si sovrappone a chi lo ha aperto, che resta visibile sotto e non
|
|
155
|
+
* va nascosto. Oltre ai contesti che lo chiedono (openDcmtFormAsModal) è il caso della duplicazione,
|
|
156
|
+
* che parte da un documento a video (LayoutModes.Ark con un DID) per proporne uno nuovo da archiviare.
|
|
157
|
+
*/
|
|
158
|
+
const isDcmtFormModal = openDcmtFormAsModal || (dcmtFormLayoutMode === LayoutModes.Ark && focusedItem?.DID !== undefined);
|
|
152
159
|
const [currentCustomButton, setCurrentCustomButton] = useState();
|
|
153
160
|
// State to control the visibility of the details form
|
|
154
161
|
const [showSearchTMDatagrid, setShowSearchTMDatagrid] = useState(false);
|
|
162
|
+
const [showDcmtTypesSelection, setShowDcmtTypesSelection] = useState(false);
|
|
155
163
|
const [secondaryMasterDcmts, setSecondaryMasterDcmts] = useState([]);
|
|
156
164
|
const [isOpenSharedArchive, setIsOpenSharedArchive] = useState(false);
|
|
157
165
|
const [sharedDcmtFile, setSharedDcmtFile] = useState(undefined);
|
|
@@ -169,6 +177,7 @@ export const useDocumentOperations = (props) => {
|
|
|
169
177
|
// State to control modal opening for master/detail documents
|
|
170
178
|
const [isOpenDetailsModal, setIsOpenDetailsModal] = useState(false);
|
|
171
179
|
const [isOpenMasterModal, setIsOpenMasterModal] = useState(false);
|
|
180
|
+
const [isOpenMultiDetailModal, setIsOpenMultiDetailModal] = useState(false);
|
|
172
181
|
const openDetailDcmtsFormHandler = (value) => { setIsOpenDetails(value); };
|
|
173
182
|
const openMasterDcmtsFormHandler = (value) => { setIsOpenMaster(value); };
|
|
174
183
|
const openDetailDcmtsModalHandler = (value) => { setIsOpenDetailsModal(value); };
|
|
@@ -907,10 +916,18 @@ export const useDocumentOperations = (props) => {
|
|
|
907
916
|
id: 'rel-ark-det',
|
|
908
917
|
icon: _jsx(IconArchiveDetail, {}),
|
|
909
918
|
name: SDKUI_Localizator.ArchiveDetailDocument,
|
|
910
|
-
operationType: '
|
|
911
|
-
disabled: canArchiveDetailRelation !== true,
|
|
919
|
+
operationType: 'singleRow',
|
|
920
|
+
disabled: canArchiveDetailRelation !== true || isDisabledForMultiRow(),
|
|
912
921
|
onClick: async () => await archiveDetailDocuments(selectedDcmtInfos?.[0]?.TID)
|
|
913
922
|
},
|
|
923
|
+
{
|
|
924
|
+
id: 'multi-detail',
|
|
925
|
+
icon: _jsx(IconArchiveMultipleDetailDocuments, {}),
|
|
926
|
+
name: SDKUI_Localizator.ArchiveMultipleDetailDocuments,
|
|
927
|
+
operationType: 'singleRow',
|
|
928
|
+
disabled: canArchiveDetailRelation !== true || isDisabledForMultiRow(),
|
|
929
|
+
onClick: () => setIsOpenMultiDetailModal(true),
|
|
930
|
+
},
|
|
914
931
|
{
|
|
915
932
|
id: 'rel-mst',
|
|
916
933
|
icon: _jsx(IconDetailDcmts, { transform: 'scale(-1, 1)' }),
|
|
@@ -1054,6 +1071,7 @@ export const useDocumentOperations = (props) => {
|
|
|
1054
1071
|
]
|
|
1055
1072
|
};
|
|
1056
1073
|
};
|
|
1074
|
+
const canToggleDcmtTypesSelection = !isMobile && context === SearchResultContext.WORKFLOW_APPROVE;
|
|
1057
1075
|
const otherOperationsMenuItem = () => {
|
|
1058
1076
|
return {
|
|
1059
1077
|
id: 'oth',
|
|
@@ -1085,7 +1103,15 @@ export const useDocumentOperations = (props) => {
|
|
|
1085
1103
|
disabled: false,
|
|
1086
1104
|
onClick: () => setShowFloatingBar(prev => !prev)
|
|
1087
1105
|
}]
|
|
1088
|
-
: [])
|
|
1106
|
+
: []),
|
|
1107
|
+
{
|
|
1108
|
+
id: 'oth-dcmt-types',
|
|
1109
|
+
icon: showDcmtTypesSelection ? _jsx(IconHide, {}) : _jsx(IconShow, {}),
|
|
1110
|
+
name: showDcmtTypesSelection ? SDKUI_Localizator.HideDcmtTypes : SDKUI_Localizator.ShowDcmtTypes,
|
|
1111
|
+
visible: canToggleDcmtTypesSelection,
|
|
1112
|
+
disabled: false,
|
|
1113
|
+
onClick: () => setShowDcmtTypesSelection(prev => !prev)
|
|
1114
|
+
}
|
|
1089
1115
|
]
|
|
1090
1116
|
};
|
|
1091
1117
|
};
|
|
@@ -1345,6 +1371,10 @@ export const useDocumentOperations = (props) => {
|
|
|
1345
1371
|
dcmtUtility,
|
|
1346
1372
|
fetchRemoteCertificates
|
|
1347
1373
|
};
|
|
1374
|
+
// Navigazione del master nell'archiviazione multipla dei dettagli: il modale prende il documento
|
|
1375
|
+
// con il focus, quindi le frecce hanno senso solo senza selezione a checkbox, che ha la precedenza
|
|
1376
|
+
// sul focus e terrebbe il master fermo (vedi getSelectedDcmtsOrFocused)
|
|
1377
|
+
const canNavigateMultiDetailMaster = !!canNavigateHandler && !!onNavigateHandler && selectedItems.length === 0 && selectedDcmtInfos.length === 1;
|
|
1348
1378
|
const masterDetailMasterCommonProps = {
|
|
1349
1379
|
deviceType,
|
|
1350
1380
|
isForMaster: true,
|
|
@@ -1373,15 +1403,16 @@ export const useDocumentOperations = (props) => {
|
|
|
1373
1403
|
dcmtUtility,
|
|
1374
1404
|
fetchRemoteCertificates
|
|
1375
1405
|
};
|
|
1376
|
-
const renderDcmtOperations = (_jsxs(_Fragment, { children: [(showExportForm && searchResult && dataColumns && dataSource && selectedRowKeys) && (_jsx(TMDataGridExportForm, { dataColumns: dataColumns, dataSource: dataSource, selectedRowKeys: selectedRowKeys, onCloseExportForm: () => setShowExportForm(false), searchResult: searchResult })), _jsx(StyledMultiViewPanel, { "$isVisible": isOpenDcmtForm, children: ((isOpenDcmtForm && focusedItem?.TID !== undefined && focusedItem?.DID !== undefined) &&
|
|
1377
|
-
_jsx(TMDcmtForm, { isModal:
|
|
1406
|
+
const renderDcmtOperations = (_jsxs(_Fragment, { children: [(showExportForm && searchResult && dataColumns && dataSource && selectedRowKeys) && (_jsx(TMDataGridExportForm, { dataColumns: dataColumns, dataSource: dataSource, selectedRowKeys: selectedRowKeys, onCloseExportForm: () => setShowExportForm(false), searchResult: searchResult })), _jsx(StyledMultiViewPanel, { "$isVisible": isOpenDcmtForm && !isDcmtFormModal, children: ((isOpenDcmtForm && focusedItem?.TID !== undefined && focusedItem?.DID !== undefined) &&
|
|
1407
|
+
_jsx(TMDcmtForm, { isModal: isDcmtFormModal, titleModal: dtd?.name ?? '', TID: focusedItem.TID, DID: focusedItem.DID, allowButtonsRefs: true, showTodoDcmtForm: showTodoDcmtForm, layoutMode: dcmtFormLayoutMode, count: visibleItems?.length, itemIndex: visibleItems ? visibleItems.findIndex(o => o.rowIndex === focusedItem?.rowIndex) + 1 : undefined, canNext: canNavigateHandler ? canNavigateHandler('next') : false, canPrev: canNavigateHandler ? canNavigateHandler('prev') : false, onNext: () => onNavigateHandler && onNavigateHandler('next'), onPrev: () => onNavigateHandler && onNavigateHandler('prev'), onClose: () => { (false); onDcmtFormOpenChange(false, LayoutModes.Update); }, onWFOperationCompleted: onWFOperationCompleted, onTaskCreateRequest: onTaskCreateRequest, onSavedAsyncCallback: onSavedAsyncCallback, openS4TViewer: openS4TViewer, onOpenS4TViewerRequest: onOpenS4TViewerRequest, editPdfForm: editPdfForm, onOpenPdfEditorRequest: onOpenPdfEditorRequest, openFileUploaderPdfEditor: openFileUploaderPdfEditor, onReferenceClick: onReferenceClick, allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback, editTaskCallback: editTaskCallback, handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers, moreInfoTasks: getMoreInfoTasksForDocument(allTasks, focusedItem?.TID, focusedItem?.DID), showDcmtFormSidebar: showDcmtFormSidebar, datagridUtility: {
|
|
1378
1408
|
onRefreshSearchAsyncDatagrid,
|
|
1379
1409
|
onRefreshDataRowsAsync,
|
|
1380
1410
|
refreshFocusedDataRowAsync,
|
|
1381
1411
|
onRefreshBlogDatagrid,
|
|
1382
1412
|
onRefreshPreviewDatagrid
|
|
1383
1413
|
}, fetchRemoteCertificates: fetchRemoteCertificates, graphometricManager: graphometricManager })) }), (showHistory && dtd && selectedDcmtInfos.length > 0) && _jsx(TMViewHistoryDcmt, { fromDTD: dtd, deviceType: deviceType, inputDcmt: selectedDcmtInfos[0], onClose: hideHistoryCallback, allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback, editTaskCallback: editTaskCallback, handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers }), (commentFormState.show && selectedDcmtInfos.length > 0) && _jsx(TMBlogCommentForm, { context: { engine: 'SearchEngine', object: { tid: selectedDcmtInfos[0].TID, did: selectedDcmtInfos[0].DID } }, onClose: hideCommentFormCallback, refreshCallback: onRefreshBlog, participants: [], showAttachmentsSection: true, allArchivedDocumentsFileItems: convertSearchResultDescriptorToFileItems(currentSearchResults ?? []), isCommentRequired: commentFormState.isRequired, removeAndEditAttachment: commentFormState.removeAndEditAttachment, selectedAttachmentDid: [Number(selectedDcmtInfos[0].DID)] }), (showCheckoutInformationForm && dtd && selectedDcmtInfos.length > 0) &&
|
|
1384
|
-
_jsx(TMDcmtCheckoutInfoForm, { dtdName: dtd.name ?? SDKUI_Localizator.SearchResult, selectedDcmtOrFocused: selectedDcmtInfos[0], onClose: hideCheckoutInformationFormCallback }), isOpenDetailsModal && _jsx(TMModal, { width: "95%", height: "95%", onClose: () => setIsOpenDetailsModal(false), title: SDKUI_Localizator.Relations, children: _jsx(TMMasterDetailDcmts, { ...masterDetailDetailsCommonProps, onBack: () => setIsOpenDetailsModal(false) }) }), _jsx(StyledMultiViewPanel, { "$isVisible": isOpenDetails, children: isOpenDetails && _jsx(TMMasterDetailDcmts, { ...masterDetailDetailsCommonProps, onBack: () => setIsOpenDetails(false) }) }),
|
|
1414
|
+
_jsx(TMDcmtCheckoutInfoForm, { dtdName: dtd.name ?? SDKUI_Localizator.SearchResult, selectedDcmtOrFocused: selectedDcmtInfos[0], onClose: hideCheckoutInformationFormCallback }), isOpenDetailsModal && _jsx(TMModal, { width: "95%", height: "95%", onClose: () => setIsOpenDetailsModal(false), title: SDKUI_Localizator.Relations, children: _jsx(TMMasterDetailDcmts, { ...masterDetailDetailsCommonProps, onBack: () => setIsOpenDetailsModal(false) }) }), _jsx(StyledMultiViewPanel, { "$isVisible": isOpenDetails, children: isOpenDetails && _jsx(TMMasterDetailDcmts, { ...masterDetailDetailsCommonProps, onBack: () => setIsOpenDetails(false) }) }), (isOpenMultiDetailModal && dtd) &&
|
|
1415
|
+
_jsx(TMMultiMasterDetailDcmtsForm, { dtd: dtd, masterDcmt: selectedDcmtInfos[0], onClose: () => setIsOpenMultiDetailModal(false), canNavigateMaster: canNavigateMultiDetailMaster ? canNavigateHandler : undefined, onNavigateMaster: canNavigateMultiDetailMaster ? onNavigateHandler : undefined, allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback, editTaskCallback: editTaskCallback, handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers, showDcmtFormSidebar: showDcmtFormSidebar, showTodoDcmtForm: showTodoDcmtForm, openFileUploaderPdfEditor: openFileUploaderPdfEditor, graphometricManager: graphometricManager, editPdfForm: editPdfForm, openS4TViewer: openS4TViewer, showToppyDraggableHelpCenter: showToppyDraggableHelpCenter, toppyHelpCenterUsePortal: toppyHelpCenterUsePortal, fetchRemoteCertificates: fetchRemoteCertificates, onOpenS4TViewerRequest: onOpenS4TViewerRequest, onOpenPdfEditorRequest: onOpenPdfEditorRequest, onReferenceClick: onReferenceClick, onTaskCreateRequest: onTaskCreateRequest, onRefreshAfterAddDcmtToFavs: onRefreshAfterAddDcmtToFavs, onFileOpened: onFileOpened, passToArchiveCallback: passToArchiveCallback, openWGsCopyMoveForm: openWGsCopyMoveForm }), isOpenMasterModal && _jsx(TMModal, { width: "95%", height: "95%", onClose: () => setIsOpenMasterModal(false), title: SDKUI_Localizator.Relations, children: _jsx(TMMasterDetailDcmts, { ...masterDetailMasterCommonProps, onBack: () => setIsOpenMasterModal(false) }) }), _jsxs(StyledMultiViewPanel, { "$isVisible": isOpenMaster, children: [isOpenMaster && _jsx(TMMasterDetailDcmts, { ...masterDetailMasterCommonProps, onBack: () => setIsOpenMaster(false) }), secondaryMasterDcmts.length > 0 && secondaryMasterDcmts.map((dcmt, index) => {
|
|
1385
1416
|
return (_jsx(StyledModalContainer, { style: { backgroundColor: 'white' }, children: _jsx(TMMasterDetailDcmts, { ...masterDetailMasterCommonProps, inputDcmts: [dcmt], allowNavigation: false, onBack: () => handleRemoveItem(dcmt.TID, dcmt.DID) }) }, `${index}-${dcmt.DID}`));
|
|
1386
1417
|
})] }), isOpenArchiveRelationForm && _jsx(TMDcmtForm, { isModal: true, titleModal: SDKUI_Localizator.Archive + ' - ' + (archiveType === 'detail' ? SDKUI_Localizator.DcmtsDetail : SDKUI_Localizator.DcmtsMaster), TID: archiveRelatedDcmtFormTID, layoutMode: LayoutModes.Ark, inputMids: archiveRelatedDcmtFormMids, showBackButton: false, allowButtonsRefs: false, onClose: () => {
|
|
1387
1418
|
setIsOpenArchiveRelationForm(false);
|
|
@@ -1389,10 +1420,15 @@ export const useDocumentOperations = (props) => {
|
|
|
1389
1420
|
setArchiveRelatedDcmtFormTID(undefined);
|
|
1390
1421
|
setArchiveRelatedDcmtFormMids([]);
|
|
1391
1422
|
}, onSavedAsyncCallback: async (tid, did, metadataResult) => {
|
|
1423
|
+
const originDcmt = selectedDcmtInfos?.[0];
|
|
1392
1424
|
setIsOpenArchiveRelationForm(false);
|
|
1393
1425
|
setArchiveType(undefined);
|
|
1394
1426
|
setArchiveRelatedDcmtFormTID(undefined);
|
|
1395
1427
|
setArchiveRelatedDcmtFormMids([]);
|
|
1428
|
+
if (refreshFocusedDataRowAsync && originDcmt?.TID && originDcmt?.DID) {
|
|
1429
|
+
await refreshFocusedDataRowAsync(originDcmt.TID, originDcmt.DID, true);
|
|
1430
|
+
return;
|
|
1431
|
+
}
|
|
1396
1432
|
await onRefreshSearchAsyncDatagrid?.();
|
|
1397
1433
|
}, allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback, editTaskCallback: editTaskCallback, handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers, showDcmtFormSidebar: showDcmtFormSidebar, openFileUploaderPdfEditor: openFileUploaderPdfEditor, showTodoDcmtForm: showTodoDcmtForm, graphometricManager: graphometricManager }), showRelatedDcmtsChooser &&
|
|
1398
1434
|
_jsx(TMChooserForm, { dataSource: relatedDcmtsChooserDataSource, onChoose: async (selectedRelation) => {
|
|
@@ -1427,8 +1463,8 @@ export const useDocumentOperations = (props) => {
|
|
|
1427
1463
|
TMSpinner.hide();
|
|
1428
1464
|
}
|
|
1429
1465
|
}, onClose: () => setShowManyToManyChooser(false), manageUseLocalizedName: false }), showPairDcmtsModal &&
|
|
1430
|
-
_jsx(TMModal, { title:
|
|
1431
|
-
_jsx(TMModal, { title:
|
|
1466
|
+
_jsx(TMModal, { title: isPairingManyToMany ? SDKUI_Localizator.MatchDcmts : SDKUI_Localizator.UnmatchDcmts, onClose: () => setShowPairDcmtsModal(false), width: '95%', height: '95%', children: _jsx(TMSearchResult, { searchResults: pairedSearchResults, onRefreshAfterAddDcmtToFavs: onRefreshAfterAddDcmtToFavs, onRefreshSearchAsyncDatagrid: onRefreshSearchAsyncDatagrid, onFileOpened: onFileOpened, onTaskCreateRequest: onTaskCreateRequest, openWGsCopyMoveForm: openWGsCopyMoveForm, editPdfForm: editPdfForm, openS4TViewer: openS4TViewer, onOpenS4TViewerRequest: onOpenS4TViewerRequest, onOpenPdfEditorRequest: onOpenPdfEditorRequest, passToArchiveCallback: passToArchiveCallback, showTodoDcmtForm: showTodoDcmtForm, allowFloatingBar: false, floatingActionConfig: pairFloatingActionConfig, showBackButton: backToPairSearchModal !== undefined, onClose: backToPairSearchModal, backCaption: SDKUI_Localizator.BackToSearch, allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback, editTaskCallback: editTaskCallback, handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers, toppyHelpCenterUsePortal: toppyHelpCenterUsePortal, showToppyDraggableHelpCenter: showToppyDraggableHelpCenter, fetchRemoteCertificates: fetchRemoteCertificates }) }), showPairSearchModal &&
|
|
1467
|
+
_jsx(TMModal, { title: SDKUI_Localizator.Search_Dcmts, onClose: () => setShowPairSearchModal(false), width: '95%', height: '95%', children: _jsx(TMSearch, { onlyShowSearchQueryPanel: true, inputTID: pairSearchModalTargetTID, inputMids: pairSearchModalInputMids, floatingActionConfig: pairSearchModalFloatingActionConfig, allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback, editTaskCallback: editTaskCallback, handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers }) }), isOpenSharedArchive && _jsx(TMModal, { title: SDKUI_Localizator.SharedArchiving, onClose: () => {
|
|
1432
1468
|
setIsOpenSharedArchive(false);
|
|
1433
1469
|
}, width: isMobile ? '90%' : '60%', height: isMobile ? '90%' : '80%', children: _jsx(TMArchive, { inputDID: selectedDcmtInfos?.[0].DID, inputTID: selectedDcmtInfos?.[0].TID, inputMids: currentMetadataValues.filter(md => md.mid && md.mid > 100).map(md => ({ mid: md.mid, value: md.value ?? '' })), isSharedArchive: true, inputFile: sharedDcmtFile, onSavedAsyncCallback: async (tid, did) => {
|
|
1434
1470
|
setIsOpenSharedArchive(false);
|
|
@@ -1446,14 +1482,17 @@ export const useDocumentOperations = (props) => {
|
|
|
1446
1482
|
} }))] }));
|
|
1447
1483
|
return {
|
|
1448
1484
|
operationItems: operationItems(),
|
|
1485
|
+
selectedDcmtInfos,
|
|
1449
1486
|
renderFloatingBar,
|
|
1450
1487
|
renderDcmtOperations,
|
|
1451
1488
|
features: {
|
|
1452
1489
|
isOpenDcmtForm,
|
|
1490
|
+
isDcmtFormModal,
|
|
1453
1491
|
openFormHandler,
|
|
1454
1492
|
dcmtFormLayoutMode,
|
|
1455
1493
|
onDcmtFormOpenChange,
|
|
1456
1494
|
showSearchTMDatagrid,
|
|
1495
|
+
showDcmtTypesSelection,
|
|
1457
1496
|
showExportForm,
|
|
1458
1497
|
isOpenBatchUpdate,
|
|
1459
1498
|
isModifiedBatchUpdate,
|
|
@@ -1521,6 +1560,7 @@ export const useDocumentOperations = (props) => {
|
|
|
1521
1560
|
canArchiveDetailRelation,
|
|
1522
1561
|
hasManyToManyRelation,
|
|
1523
1562
|
showPairDcmtsModal,
|
|
1563
|
+
backToPairSearchModal,
|
|
1524
1564
|
// Pair search modal state
|
|
1525
1565
|
pairSearchModalTargetTID,
|
|
1526
1566
|
pairSearchModalParentTID,
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { DcmtTypeDescriptor, RelationDescriptor, SearchResultDescriptor } from '@topconsultnpm/sdk-ts';
|
|
2
|
+
import { IColumnProps } from 'devextreme-react/data-grid';
|
|
3
|
+
import { DcmtInfo, MetadataValueDescriptorEx } from '../ts';
|
|
4
|
+
import { AccordionSection, ArchiveRow, ArchiveRowChanges, DetailRelationItem, MetadataScalarValue } from '../components/features/documents/TMMultiMasterDetailDcmtsUtils';
|
|
5
|
+
/** Fasi del flusso di archiviazione multipla dei dettagli */
|
|
6
|
+
export declare enum MultiDetailArchivePhase {
|
|
7
|
+
/** Scelta del tipo documento */
|
|
8
|
+
SelectDcmtType = 0,
|
|
9
|
+
/** Riepilogo delle archiviazioni */
|
|
10
|
+
ArchiveSummary = 1
|
|
11
|
+
}
|
|
12
|
+
/** Riga di riepilogo: definita con i tipi della feature (vedi TMMultiMasterDetailDcmtsUtils) */
|
|
13
|
+
export type { ArchiveRow };
|
|
14
|
+
/** Coppia mid/valore per pre-compilare il form */
|
|
15
|
+
export type MidValue = {
|
|
16
|
+
mid: number;
|
|
17
|
+
value: string;
|
|
18
|
+
};
|
|
19
|
+
/** Stato del wait panel: le chiavi sono quelle dei props di TMLayoutWaitingContainer */
|
|
20
|
+
export type WaitPanelState = {
|
|
21
|
+
showWaitPanel: boolean;
|
|
22
|
+
waitPanelTitle: string;
|
|
23
|
+
showWaitPanelPrimary: boolean;
|
|
24
|
+
waitPanelTextPrimary: string;
|
|
25
|
+
waitPanelValuePrimary: number;
|
|
26
|
+
waitPanelMaxValuePrimary: number;
|
|
27
|
+
showWaitPanelSecondary: boolean;
|
|
28
|
+
waitPanelTextSecondary: string;
|
|
29
|
+
waitPanelValueSecondary: number;
|
|
30
|
+
waitPanelMaxValueSecondary: number;
|
|
31
|
+
};
|
|
32
|
+
interface UseMultiMasterDetailDcmtsParams {
|
|
33
|
+
/** Tipo documento del master */
|
|
34
|
+
dtd: DcmtTypeDescriptor;
|
|
35
|
+
/** Documento master da cui parte l'archiviazione dei dettagli */
|
|
36
|
+
masterDcmt: DcmtInfo;
|
|
37
|
+
/** Chiusura del modale */
|
|
38
|
+
onClose: () => void;
|
|
39
|
+
/** true se nella lista di provenienza c'è un documento precedente/successivo su cui spostare il master */
|
|
40
|
+
canNavigateMaster?: (dir: 'next' | 'prev') => boolean;
|
|
41
|
+
/** Sposta il focus della lista di provenienza: il master arriva da lì e cambia da sé (vedi masterDcmt) */
|
|
42
|
+
onNavigateMaster?: (dir: 'next' | 'prev') => void;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Logica dell'archiviazione multipla dei dettagli: relazioni, sezioni, righe del riepilogo e
|
|
46
|
+
* archiviazione. Il rendering sta in TMMultiMasterDetailDcmtsForm
|
|
47
|
+
*/
|
|
48
|
+
export declare const useMultiMasterDetailDcmts: ({ dtd, masterDcmt, onClose, canNavigateMaster, onNavigateMaster }: UseMultiMasterDetailDcmtsParams) => {
|
|
49
|
+
isLoading: boolean;
|
|
50
|
+
isSummaryReady: boolean;
|
|
51
|
+
phase: MultiDetailArchivePhase;
|
|
52
|
+
setPhase: import("react").Dispatch<import("react").SetStateAction<MultiDetailArchivePhase>>;
|
|
53
|
+
detailRelationItems: DetailRelationItem[];
|
|
54
|
+
selectedRelation: RelationDescriptor | undefined;
|
|
55
|
+
selectedItem: DetailRelationItem | undefined;
|
|
56
|
+
hasMultipleTypes: boolean;
|
|
57
|
+
selectRelation: (item: DetailRelationItem) => void;
|
|
58
|
+
backToTypeSelection: () => void;
|
|
59
|
+
isBackLocked: boolean;
|
|
60
|
+
closeModal: () => void;
|
|
61
|
+
isMasterNavigationEnabled: boolean;
|
|
62
|
+
canNavigateMasterPrev: boolean;
|
|
63
|
+
canNavigateMasterNext: boolean;
|
|
64
|
+
navigateMaster: (dir: "next" | "prev") => void;
|
|
65
|
+
sectionsOpen: Record<AccordionSection, boolean>;
|
|
66
|
+
setSectionOpen: (section: AccordionSection, isOpen: boolean) => void;
|
|
67
|
+
openAllSections: () => void;
|
|
68
|
+
clearLayout: () => void;
|
|
69
|
+
layoutResetToken: number;
|
|
70
|
+
hasSavedLayout: boolean;
|
|
71
|
+
setHasSavedLayout: import("react").Dispatch<import("react").SetStateAction<boolean>>;
|
|
72
|
+
canUpdateMaster: boolean;
|
|
73
|
+
masterFieldsCount: number;
|
|
74
|
+
getMasterMetadataAsync: () => Promise<Map<number, MetadataScalarValue>>;
|
|
75
|
+
masterInfoReloadToken: number;
|
|
76
|
+
isOpenMasterForm: boolean;
|
|
77
|
+
setIsOpenMasterForm: import("react").Dispatch<import("react").SetStateAction<boolean>>;
|
|
78
|
+
handleMasterSavedAsync: () => Promise<void>;
|
|
79
|
+
archivedDetailResults: SearchResultDescriptor[];
|
|
80
|
+
archivedDetailsCount: number;
|
|
81
|
+
isLoadingArchivedDetails: boolean;
|
|
82
|
+
refreshArchivedDetailsAsync: () => Promise<void>;
|
|
83
|
+
detailColumns: IColumnProps[];
|
|
84
|
+
detailSupportsFile: boolean;
|
|
85
|
+
archiveRows: ArchiveRow[];
|
|
86
|
+
currentRows: ArchiveRow[];
|
|
87
|
+
focusedRowKey: number | undefined;
|
|
88
|
+
setFocusedRowKey: import("react").Dispatch<import("react").SetStateAction<number | undefined>>;
|
|
89
|
+
selectedRowKeys: number[];
|
|
90
|
+
setSelectedRowKeys: import("react").Dispatch<import("react").SetStateAction<number[]>>;
|
|
91
|
+
isOpenAddForm: boolean;
|
|
92
|
+
editingRowId: number | undefined;
|
|
93
|
+
editingRow: ArchiveRow | undefined;
|
|
94
|
+
formInputMids: MidValue[];
|
|
95
|
+
openAddForm: () => void;
|
|
96
|
+
openEditForm: (row: ArchiveRow | undefined) => void;
|
|
97
|
+
closeAddForm: () => void;
|
|
98
|
+
deleteRow: (row: ArchiveRow | undefined) => void;
|
|
99
|
+
duplicateRow: (row: ArchiveRow | undefined) => void;
|
|
100
|
+
upsertRow: (values: Array<MetadataValueDescriptorEx>, file: File | undefined) => void;
|
|
101
|
+
updateRowValues: (rowId: number, changes: ArchiveRowChanges) => void;
|
|
102
|
+
copyArchivedDetailToRows: (dcmt: {
|
|
103
|
+
TID?: number | string;
|
|
104
|
+
DID?: number | string;
|
|
105
|
+
FILEEXT?: string;
|
|
106
|
+
} | undefined) => Promise<void>;
|
|
107
|
+
stopOnFirstError: boolean;
|
|
108
|
+
setStopOnFirstError: import("react").Dispatch<import("react").SetStateAction<boolean>>;
|
|
109
|
+
isArchiving: boolean;
|
|
110
|
+
archiveAllAsync: () => Promise<void>;
|
|
111
|
+
waitPanel: WaitPanelState;
|
|
112
|
+
abortController: AbortController | undefined;
|
|
113
|
+
};
|