@topconsultnpm/sdkui-react 6.22.0-dev2.3 → 6.22.0-dev2.30
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/TMButton.d.ts +13 -0
- package/lib/components/base/TMButton.js +137 -5
- package/lib/components/base/TMDataGrid.d.ts +2 -0
- package/lib/components/base/TMDataGrid.js +81 -8
- package/lib/components/base/TMEditorBase.d.ts +2 -0
- package/lib/components/base/TMFileManager.js +5 -3
- package/lib/components/base/TMFileManagerUtils.d.ts +1 -0
- package/lib/components/base/TMFileManagerUtils.js +16 -0
- package/lib/components/base/TMModal.d.ts +4 -0
- package/lib/components/base/TMModal.js +42 -11
- package/lib/components/base/TMPanel.d.ts +1 -0
- package/lib/components/base/TMPanel.js +79 -20
- package/lib/components/base/TMPopUp.js +3 -0
- package/lib/components/base/TMTooltip.d.ts +2 -1
- package/lib/components/base/TMTooltip.js +23 -6
- 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/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 +112 -45
- package/lib/components/features/documents/TMDcmtFormActionButtons.d.ts +11 -0
- package/lib/components/features/documents/TMDcmtFormActionButtons.js +74 -7
- 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/TMMultiMasterDetailDcmtsForm.d.ts +40 -0
- package/lib/components/features/documents/TMMultiMasterDetailDcmtsForm.js +296 -0
- package/lib/components/features/documents/TMMultiMasterDetailDcmtsUtils.d.ts +363 -0
- package/lib/components/features/documents/TMMultiMasterDetailDcmtsUtils.js +259 -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 +29 -16
- package/lib/components/features/search/TMSearchQueryEditor.js +5 -3
- package/lib/components/features/search/TMSearchQueryPanel.d.ts +1 -1
- package/lib/components/features/search/TMSearchQueryPanel.js +28 -7
- package/lib/components/features/search/TMSearchResult.d.ts +9 -0
- package/lib/components/features/search/TMSearchResult.js +419 -108
- package/lib/components/features/search/TMTreeSelector.js +18 -5
- package/lib/components/features/workflow/TMWorkflowPopup.d.ts +10 -0
- package/lib/components/features/workflow/TMWorkflowPopup.js +8 -4
- 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/viewers/TMMidViewer.js +4 -1
- package/lib/components/viewers/TMTidViewer.js +25 -11
- package/lib/helper/SDKUI_Globals.d.ts +82 -0
- package/lib/helper/SDKUI_Globals.js +119 -0
- package/lib/helper/SDKUI_Localizator.d.ts +24 -0
- package/lib/helper/SDKUI_Localizator.js +240 -0
- package/lib/helper/TMIcons.d.ts +1 -0
- package/lib/helper/TMIcons.js +3 -0
- 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 +20 -0
- package/lib/helper/helpers.js +55 -1
- package/lib/helper/index.d.ts +1 -0
- package/lib/helper/index.js +1 -0
- package/lib/helper/queryHelper.d.ts +2 -0
- package/lib/helper/queryHelper.js +3 -1
- 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 +2 -0
- package/lib/hooks/useDocumentOperations.js +28 -5
- package/lib/hooks/useMultiMasterDetailDcmts.d.ts +100 -0
- package/lib/hooks/useMultiMasterDetailDcmts.js +587 -0
- package/lib/hooks/useRelatedDocuments.js +2 -26
- 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 +1 -0
- package/lib/index.js +1 -0
- 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 +66 -66
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
3
|
+
import { LayoutModes } from "@topconsultnpm/sdk-ts";
|
|
4
|
+
import { LoadIndicator } from "devextreme-react/load-indicator";
|
|
5
|
+
import { SearchResultContext } from "../../../ts";
|
|
6
|
+
import { getFullFileExtension, getMultiDetailPanelStates, hasMultiDetailPanelStates, hoverStyle, IconArchive, IconDelete, IconDuplicate, IconEdit, IconEraser, IconInfo, IconMenuVertical, IconRefresh, IconSearch, IconSearchCheck, saveMultiDetailPanelStates, SDKUI_Localizator } from "../../../helper";
|
|
7
|
+
import { TMColors } from "../../../utils/theme";
|
|
8
|
+
import { DeviceType, useDeviceType } from "../../base/TMDeviceProvider";
|
|
9
|
+
import { TMLayoutWaitingContainer } from "../../base/TMWaitPanel";
|
|
10
|
+
import TMModal from "../../base/TMModal";
|
|
11
|
+
import TMDataGrid from "../../base/TMDataGrid";
|
|
12
|
+
import TMTooltip from "../../base/TMTooltip";
|
|
13
|
+
import { TMDcmtTypeIcon } from "../../viewers/TMTidViewer";
|
|
14
|
+
import { ContextMenu } from "../../NewComponents/ContextMenu";
|
|
15
|
+
import { TMPanelManagerWithPersistenceProvider } from "../../layout/panelManager/TMPanelManagerWithPersistenceProvider";
|
|
16
|
+
import TMPanelManagerContainer from "../../layout/panelManager/TMPanelManagerContainer";
|
|
17
|
+
import TMSearchResult from "../search/TMSearchResult";
|
|
18
|
+
import TMDcmtForm from "./TMDcmtForm";
|
|
19
|
+
import TMDcmtIcon from "./TMDcmtIcon";
|
|
20
|
+
import TMMasterInfoFields from "./TMMasterInfoFields";
|
|
21
|
+
import { MultiDetailArchivePhase, useMultiMasterDetailDcmts } from "../../../hooks/useMultiMasterDetailDcmts";
|
|
22
|
+
import { accordionStyles, getDtdDisplayName, INLINE_EDITABLE_CELL_CLASS, multiDetailStyles, PANEL_GUTTER_PX, renderAccordionHeader, renderSelectDcmtType, renderStepper, SECTION_HEADER_HEIGHT_PX, sectionPanelHeights, TMSectionPanelsHeights, TMSummaryResizeTracker, TMSummarySectionSlot } from "./TMMultiMasterDetailDcmtsUtils";
|
|
23
|
+
// Stili delle sezioni in TMMultiMasterDetailDcmtsUtils (vedi accordionStyles e multiDetailStyles)
|
|
24
|
+
const styles = {
|
|
25
|
+
content: { display: 'flex', flexDirection: 'column', height: '100%', minHeight: 0 },
|
|
26
|
+
header: { display: 'flex', alignItems: 'center', justifyContent: 'center', padding: '6px 12px', borderBottom: `1px solid ${TMColors.card_background}`, flexShrink: 0 },
|
|
27
|
+
// Opzioni nella barra del titolo: stesse misure e colore della chiusura DevExtreme (.dx-popup-title .dx-closebutton)
|
|
28
|
+
titleMenuIcon: { display: 'inline-flex', alignItems: 'center', justifyContent: 'center', width: '18px', height: '18px', margin: '1px 0 0', color: `var(--dx-color-text, ${TMColors.text_normal})`, cursor: 'pointer' },
|
|
29
|
+
loader: { display: 'flex', flex: 1, alignItems: 'center', justifyContent: 'center' },
|
|
30
|
+
summaryContainer: { display: 'flex', flexDirection: 'column', flex: 1, padding: '8px 12px 10px', minHeight: 0, gap: '8px' },
|
|
31
|
+
// I pannelli ripartiscono l'altezza in percentuale: serve un'altezza definita che non dipenda dal
|
|
32
|
+
// contenuto, da qui il riempimento in posizione assoluta dello spazio residuo
|
|
33
|
+
panelsHost: { position: 'relative', flex: 1, minHeight: 0, minWidth: 0 },
|
|
34
|
+
panelsHostFill: { position: 'absolute', top: 0, right: 0, bottom: 0, left: 0, display: 'flex' },
|
|
35
|
+
gridWrapper: { position: 'relative', flex: 1, minHeight: 0 },
|
|
36
|
+
actionsCell: { display: 'flex', alignItems: 'center', justifyContent: 'center', gap: '14px' },
|
|
37
|
+
actionIcon: { cursor: 'pointer', display: 'flex' },
|
|
38
|
+
fileCell: { overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' },
|
|
39
|
+
fab: { position: 'absolute', bottom: '18px', right: '20px', width: '42px', height: '42px', borderRadius: '50%', backgroundColor: TMColors.button_floating_background, color: '#fff', border: 'none', cursor: 'pointer', boxShadow: '0 2px 6px rgba(0,0,0,0.2)', zIndex: 1000, transition: 'background-color 0.3s ease, transform 0.2s ease', display: 'flex', justifyContent: 'center', alignItems: 'center' },
|
|
40
|
+
footer: { display: 'flex', flexDirection: 'row', alignItems: 'center', justifyContent: 'center', flexWrap: 'wrap', gap: '14px', paddingTop: '8px', borderTop: `1px solid ${TMColors.card_background}`, flexShrink: 0 },
|
|
41
|
+
footerLabel: { display: 'inline-flex', alignItems: 'center', gap: '8px', cursor: 'pointer', color: TMColors.label_normal, fontSize: '12px', userSelect: 'none', padding: '5px 10px', borderRadius: '16px', background: 'transparent', border: `1px solid ${TMColors.card_background}`, transition: 'all 0.15s ease' },
|
|
42
|
+
archiveButton: { display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: '8px', height: '38px', padding: '0 22px', border: 'none', borderRadius: '10px', fontSize: '14px', fontWeight: 600, letterSpacing: '0.2px', color: '#ffffff', cursor: 'pointer', transition: 'transform 0.15s ease, box-shadow 0.15s ease, background 0.15s ease' },
|
|
43
|
+
checkbox: { width: '16px', height: '16px', accentColor: TMColors.primary, cursor: 'pointer', margin: 0 },
|
|
44
|
+
};
|
|
45
|
+
/** Sezione mostrata per prima su mobile, dove i pannelli si vedono uno alla volta */
|
|
46
|
+
const MOBILE_SECTION = 'archiveList';
|
|
47
|
+
const TMMultiMasterDetailDcmtsForm = (props) => {
|
|
48
|
+
const { dtd, masterDcmt, onClose, allTasks, getAllTasks, deleteTaskByIdsCallback, addTaskCallback, editTaskCallback, handleNavigateToWGs, handleNavigateToDossiers, showDcmtFormSidebar, showTodoDcmtForm, openFileUploaderPdfEditor, graphometricManager, editPdfForm, openS4TViewer, showToppyDraggableHelpCenter, toppyHelpCenterUsePortal, fetchRemoteCertificates, onOpenS4TViewerRequest, onOpenPdfEditorRequest, onReferenceClick, onTaskCreateRequest, onRefreshAfterAddDcmtToFavs, onFileOpened, passToArchiveCallback, openWGsCopyMoveForm } = props;
|
|
49
|
+
const { isLoading, isSummaryReady, phase, setPhase, detailRelationItems, selectedRelation, selectedItem, hasMultipleTypes, selectRelation, backToTypeSelection, isBackLocked, closeModal, sectionsOpen, setSectionOpen, openAllSections, clearLayout, layoutResetToken, hasSavedLayout, setHasSavedLayout, canUpdateMaster, masterFieldsCount, getMasterMetadataAsync, masterInfoReloadToken, isOpenMasterForm, setIsOpenMasterForm, handleMasterSavedAsync, archivedDetailResults, archivedDetailsCount, isLoadingArchivedDetails, refreshArchivedDetailsAsync, detailColumns, detailSupportsFile, archiveRows, currentRows, focusedRowKey, setFocusedRowKey, selectedRowKeys, setSelectedRowKeys, isOpenAddForm, editingRowId, editingRow, formInputMids, openAddForm, openEditForm, closeAddForm, deleteRow, duplicateRow, upsertRow, updateRowValues, stopOnFirstError, setStopOnFirstError, isArchiving, archiveAllAsync, waitPanel, abortController, } = useMultiMasterDetailDcmts({ dtd, masterDcmt, onClose });
|
|
50
|
+
const deviceType = useDeviceType();
|
|
51
|
+
// Su mobile il panel manager mostra un pannello alla volta: le sezioni si raggiungono dalla sua barra
|
|
52
|
+
const isMobile = useMemo(() => deviceType === DeviceType.MOBILE, [deviceType]);
|
|
53
|
+
// Un pannello alla volta non lascia spazio da cedere: le sezioni chiuse nella vista impilata si
|
|
54
|
+
// aprono qui, altrimenti il pannello a schermo mostrerebbe la sola testata
|
|
55
|
+
useEffect(() => {
|
|
56
|
+
if (isMobile && isSummaryReady)
|
|
57
|
+
openAllSections();
|
|
58
|
+
}, [isMobile, isSummaryReady]);
|
|
59
|
+
// Le altezze sono una scelta dell'utente solo da quando sposta un separatore: quelle calcolate all'apertura
|
|
60
|
+
// o al collasso di una sezione non vanno salvate. Con un layout già salvato lo sono comunque
|
|
61
|
+
const hasUserResizedRef = useRef(false);
|
|
62
|
+
useEffect(() => { hasUserResizedRef.current = hasMultiDetailPanelStates(); }, [layoutResetToken]);
|
|
63
|
+
const persistPanelStatesOnUserResize = useCallback((panelStates) => {
|
|
64
|
+
if (!hasUserResizedRef.current)
|
|
65
|
+
return;
|
|
66
|
+
saveMultiDetailPanelStates(panelStates);
|
|
67
|
+
setHasSavedLayout(true);
|
|
68
|
+
}, []);
|
|
69
|
+
// Ricerca nella griglia dei dettagli da archiviare, come in TMSearch (vedi useDocumentOperations)
|
|
70
|
+
const [showGridSearch, setShowGridSearch] = useState(false);
|
|
71
|
+
const toggleGridSearchItem = {
|
|
72
|
+
name: showGridSearch ? SDKUI_Localizator.HideSearch : SDKUI_Localizator.ShowSearch,
|
|
73
|
+
icon: _jsx(IconSearch, { fontSize: 18 }),
|
|
74
|
+
beginGroup: true,
|
|
75
|
+
onClick: () => setShowGridSearch(prev => !prev),
|
|
76
|
+
};
|
|
77
|
+
const isSummaryPhase = phase === MultiDetailArchivePhase.ArchiveSummary;
|
|
78
|
+
const baseTitle = SDKUI_Localizator.ArchiveMultipleDetailDocuments;
|
|
79
|
+
// Con un solo tipo il nome è mostrato direttamente nel titolo del modale
|
|
80
|
+
const modalTitle = !hasMultipleTypes && selectedItem ? `${baseTitle}: ${getDtdDisplayName(selectedItem.detailDtd)}` : baseTitle;
|
|
81
|
+
const isArchiveDisabled = isArchiving || currentRows.length === 0;
|
|
82
|
+
const archiveButtonCaption = currentRows.length > 0
|
|
83
|
+
? `${SDKUI_Localizator.Archive} ${currentRows.length} ${currentRows.length === 1 ? 'dettaglio' : 'dettagli'}`
|
|
84
|
+
: SDKUI_Localizator.Archive;
|
|
85
|
+
const steps = [
|
|
86
|
+
...(hasMultipleTypes ? [{ phase: MultiDetailArchivePhase.SelectDcmtType, label: SDKUI_Localizator.DcmtType }] : []),
|
|
87
|
+
{
|
|
88
|
+
phase: MultiDetailArchivePhase.ArchiveSummary,
|
|
89
|
+
// Nel riepilogo lo step mostra il tipo selezionato (icona + nome)
|
|
90
|
+
label: selectedItem
|
|
91
|
+
? (_jsxs("span", { style: multiDetailStyles.stepTypeLabel, children: [_jsx(TMDcmtTypeIcon, { dtd: selectedItem.detailDtd }), _jsx("span", { style: multiDetailStyles.stepTypeLabelText, children: getDtdDisplayName(selectedItem.detailDtd) })] }))
|
|
92
|
+
: SDKUI_Localizator.Summary,
|
|
93
|
+
},
|
|
94
|
+
];
|
|
95
|
+
// Colonne della griglia: icona del documento, metadati del tipo, file e azioni
|
|
96
|
+
const gridColumns = useMemo(() => {
|
|
97
|
+
const iconColumn = {
|
|
98
|
+
caption: '', width: 50, alignment: 'center',
|
|
99
|
+
allowSorting: false, allowFiltering: false, allowResizing: false, allowReordering: false, allowHiding: false, allowEditing: false,
|
|
100
|
+
cellRender: (cell) => {
|
|
101
|
+
const file = cell.data?.__file;
|
|
102
|
+
return _jsx(TMDcmtIcon, { fileExtension: file ? getFullFileExtension(file.name) : undefined, fileCount: file ? 1 : 0, tooltipContent: file?.name });
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
const fileColumn = {
|
|
106
|
+
caption: 'File', width: 220, allowSorting: false, allowEditing: false,
|
|
107
|
+
cellRender: (cell) => {
|
|
108
|
+
const file = cell.data?.__file;
|
|
109
|
+
return _jsx("span", { style: { ...styles.fileCell, color: file ? TMColors.text_normal : TMColors.label_normal }, children: file ? file.name : '' });
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
const actionsColumn = {
|
|
113
|
+
caption: '', width: 110, alignment: 'center',
|
|
114
|
+
allowSorting: false, allowFiltering: false, allowHeaderFiltering: false, allowResizing: false,
|
|
115
|
+
allowReordering: false, allowHiding: false, showInColumnChooser: false, allowEditing: false,
|
|
116
|
+
cssClass: 'tm-row-actions',
|
|
117
|
+
cellRender: (cell) => (_jsxs("div", { style: styles.actionsCell, children: [_jsx(TMTooltip, { content: SDKUI_Localizator.Update, children: _jsx("span", { style: styles.actionIcon, onClick: () => openEditForm(cell.data), children: _jsx(IconEdit, { fontSize: 18, color: TMColors.primary }) }) }), _jsx(TMTooltip, { content: SDKUI_Localizator.Duplicate, children: _jsx("span", { style: styles.actionIcon, onClick: () => duplicateRow(cell.data), children: _jsx(IconDuplicate, { fontSize: 18, color: TMColors.tertiary }) }) }), _jsx(TMTooltip, { content: SDKUI_Localizator.Deletion, children: _jsx("span", { style: styles.actionIcon, onClick: () => deleteRow(cell.data), children: _jsx(IconDelete, { fontSize: 18, color: TMColors.error }) }) })] })),
|
|
118
|
+
};
|
|
119
|
+
return [actionsColumn, iconColumn, ...detailColumns, ...(detailSupportsFile ? [fileColumn] : [])];
|
|
120
|
+
}, [detailColumns, detailSupportsFile]);
|
|
121
|
+
// ----- Griglia dei dettagli: opzioni e callback con identità stabile -------------------------
|
|
122
|
+
// Un nuovo riferimento a ogni render farebbe rifare a DevExtreme il setup di selezione/editing
|
|
123
|
+
const gridSelection = useMemo(() => ({ mode: 'single', showCheckBoxesMode: 'none' }), []);
|
|
124
|
+
const gridEditing = useMemo(() => ({
|
|
125
|
+
mode: 'cell',
|
|
126
|
+
allowUpdating: true,
|
|
127
|
+
allowAdding: false,
|
|
128
|
+
allowDeleting: false,
|
|
129
|
+
startEditAction: 'click',
|
|
130
|
+
selectTextOnEditStart: false,
|
|
131
|
+
}), []);
|
|
132
|
+
const handleSelectionChanged = useCallback((e) => {
|
|
133
|
+
setSelectedRowKeys(e.selectedRowKeys ?? []);
|
|
134
|
+
}, [setSelectedRowKeys]);
|
|
135
|
+
const handleFocusedRowChanged = useCallback((e) => {
|
|
136
|
+
setFocusedRowKey(e.row?.key);
|
|
137
|
+
}, [setFocusedRowKey]);
|
|
138
|
+
const handleRowUpdating = useCallback((e) => {
|
|
139
|
+
updateRowValues(e.key, e.newData);
|
|
140
|
+
}, [updateRowValues]);
|
|
141
|
+
// Il doppio clic apre il form della riga, tranne su azioni e celle modificabili in linea
|
|
142
|
+
const handleCellDblClick = useCallback((e) => {
|
|
143
|
+
if (e.rowType !== 'data')
|
|
144
|
+
return;
|
|
145
|
+
const cssClass = e.column?.cssClass ?? '';
|
|
146
|
+
if (cssClass === 'tm-row-actions' || cssClass === INLINE_EDITABLE_CELL_CLASS)
|
|
147
|
+
return;
|
|
148
|
+
openEditForm(e.data);
|
|
149
|
+
}, [openEditForm]);
|
|
150
|
+
// Menu contestuale con le stesse azioni della colonna
|
|
151
|
+
const contextMenuItems = useMemo(() => [
|
|
152
|
+
{ name: SDKUI_Localizator.Update, icon: _jsx(IconEdit, { fontSize: 18, color: TMColors.primary }), operationType: 'singleRow', onClick: (id) => openEditForm(archiveRows.find(r => r.id === id)) },
|
|
153
|
+
{ name: SDKUI_Localizator.Duplicate, icon: _jsx(IconDuplicate, { fontSize: 18, color: TMColors.tertiary }), operationType: 'singleRow', onClick: (id) => duplicateRow(archiveRows.find(r => r.id === id)) },
|
|
154
|
+
{ name: SDKUI_Localizator.Deletion, icon: _jsx(IconDelete, { fontSize: 18, color: TMColors.error }), operationType: 'singleRow', beginGroup: true, onClick: (id) => deleteRow(archiveRows.find(r => r.id === id)) },
|
|
155
|
+
toggleGridSearchItem,
|
|
156
|
+
], [archiveRows, showGridSearch]);
|
|
157
|
+
// Menu delle opzioni del modale, aperto dal pulsante a tre punti nella barra del titolo.
|
|
158
|
+
// Con il layout di default non c'è niente da cancellare, quindi la voce non compare
|
|
159
|
+
const optionsMenuItems = useMemo(() => hasSavedLayout
|
|
160
|
+
? [{ name: 'Cancella layout', icon: _jsx(IconEraser, { fontSize: 18, color: TMColors.error }), onClick: clearLayout }]
|
|
161
|
+
: [], [clearLayout, hasSavedLayout]);
|
|
162
|
+
// Le opzioni riguardano i pannelli del riepilogo: fuori da quella fase non hanno effetto, e su mobile
|
|
163
|
+
// non c'è un layout da cancellare (i pannelli si vedono uno alla volta, a tutta altezza)
|
|
164
|
+
const renderOptionsMenu = () => {
|
|
165
|
+
// Senza voci non si mostra il pulsante, per non aprire un menu vuoto
|
|
166
|
+
if (!isSummaryPhase || isMobile || optionsMenuItems.length === 0)
|
|
167
|
+
return undefined;
|
|
168
|
+
return (_jsx(ContextMenu, { trigger: 'left', items: optionsMenuItems, children: _jsx(TMTooltip, { content: SDKUI_Localizator.Options, children: _jsx("span", { style: styles.titleMenuIcon, "aria-label": SDKUI_Localizator.Options, children: _jsx(IconMenuVertical, { fontSize: 16, color: "white" }) }) }) }));
|
|
169
|
+
};
|
|
170
|
+
// ----- Sezione: informazioni del master -----------------------------------------------------
|
|
171
|
+
const renderMasterInfo = (panel) => {
|
|
172
|
+
const isOpen = sectionsOpen.masterInfo;
|
|
173
|
+
const editMasterButton = canUpdateMaster
|
|
174
|
+
? (_jsx(TMTooltip, { content: `${SDKUI_Localizator.Update}: ${getDtdDisplayName(dtd)}`, children: _jsx("button", { type: 'button', onClick: (e) => { e.stopPropagation(); setIsOpenMasterForm(true); }, style: accordionStyles.accordionExpandBtn, ...hoverStyle({ background: TMColors.primary_container, color: TMColors.primary }, { background: 'transparent', color: TMColors.label_normal }), children: _jsx(IconEdit, { fontSize: 16 }) }) }))
|
|
175
|
+
: undefined;
|
|
176
|
+
return (_jsxs("div", { style: { ...accordionStyles.accordion, ...accordionStyles.accordionInPanel }, children: [renderAccordionHeader({
|
|
177
|
+
section: 'masterInfo',
|
|
178
|
+
isOpen,
|
|
179
|
+
tooltip: isOpen ? SDKUI_Localizator.HideMasterInfo : SDKUI_Localizator.ShowMasterInfo,
|
|
180
|
+
count: masterFieldsCount,
|
|
181
|
+
title: (_jsxs(_Fragment, { children: [_jsx(TMDcmtTypeIcon, { dtd: dtd }), _jsxs("span", { style: multiDetailStyles.stepTypeLabelText, children: ["Master: ", getDtdDisplayName(dtd)] })] })),
|
|
182
|
+
actions: editMasterButton,
|
|
183
|
+
panel,
|
|
184
|
+
onToggleOpen: setSectionOpen,
|
|
185
|
+
}), isOpen && (_jsx(TMMasterInfoFields, { dtd: dtd, dcmt: masterDcmt, getValuesByMidAsync: getMasterMetadataAsync, reloadToken: masterInfoReloadToken, isExpandedView: panel.isMaximized }))] }));
|
|
186
|
+
};
|
|
187
|
+
// ----- Sezione: dettagli già archiviati -----------------------------------------------------
|
|
188
|
+
const renderArchivedDetails = (panel) => {
|
|
189
|
+
const isOpen = sectionsOpen.archivedDetails;
|
|
190
|
+
const hasResults = archivedDetailResults.length > 0 && archivedDetailsCount > 0;
|
|
191
|
+
// Ricarica i dettagli già archiviati: la sezione va aperta, altrimenti l'esito non sarebbe visibile
|
|
192
|
+
const refreshArchivedButton = (_jsx(TMTooltip, { content: SDKUI_Localizator.Refresh, children: _jsx("button", { type: 'button', onClick: (e) => { e.stopPropagation(); setSectionOpen('archivedDetails', true); refreshArchivedDetailsAsync(); }, disabled: isLoadingArchivedDetails, style: { ...accordionStyles.accordionExpandBtn, ...(isLoadingArchivedDetails ? { cursor: 'default', opacity: 0.5 } : {}) }, "aria-label": SDKUI_Localizator.Refresh, ...(isLoadingArchivedDetails ? {} : hoverStyle({ background: TMColors.primary_container, color: TMColors.primary }, { background: 'transparent', color: TMColors.label_normal })), children: _jsx(IconRefresh, { fontSize: 16 }) }) }));
|
|
193
|
+
return (_jsxs("div", { style: { ...accordionStyles.accordion, ...accordionStyles.accordionInPanel }, children: [renderAccordionHeader({
|
|
194
|
+
section: 'archivedDetails',
|
|
195
|
+
isOpen,
|
|
196
|
+
tooltip: isOpen ? SDKUI_Localizator.HideArchivedDetails : SDKUI_Localizator.ShowArchivedDetails,
|
|
197
|
+
count: archivedDetailsCount,
|
|
198
|
+
title: (_jsxs(_Fragment, { children: [_jsx(IconSearchCheck, { fontSize: 15 }), _jsx("span", { style: multiDetailStyles.stepTypeLabelText, children: SDKUI_Localizator.ArchivedDetails })] })),
|
|
199
|
+
actions: refreshArchivedButton,
|
|
200
|
+
panel,
|
|
201
|
+
onToggleOpen: setSectionOpen,
|
|
202
|
+
}), isOpen && (_jsx("div", { style: { ...accordionStyles.accordionListBody, ...(panel.isMaximized ? { borderTop: 'none' } : {}) }, children: isLoadingArchivedDetails
|
|
203
|
+
? _jsxs("div", { style: accordionStyles.accordionListPlaceholder, children: [_jsx(LoadIndicator, { height: 30, width: 30 }), SDKUI_Localizator.Loading] })
|
|
204
|
+
: (hasResults
|
|
205
|
+
? _jsx(TMSearchResult, { showToolbarHeader: false, showCounterConfig: false, showActionsColumn: true, compactPager: !panel.isMaximized, context: SearchResultContext.METADATA_SEARCH, searchResults: archivedDetailResults, onClose: () => setSectionOpen('archivedDetails', false), showBackButton: false, showToolbarCloseButton: false, allowFloatingBar: false, allowRelations: false, openDcmtFormAsModal: true, showSearchResultSidebar: false, showDcmtFormSidebar: true, autoFocusFirstRow: false, onRefreshSearchAsyncDatagrid: refreshArchivedDetailsAsync, allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback, editTaskCallback: editTaskCallback, handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers, 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 })
|
|
206
|
+
: _jsx("div", { style: accordionStyles.accordionListPlaceholder, children: SDKUI_Localizator.NoDataToDisplay })) }))] }));
|
|
207
|
+
};
|
|
208
|
+
// ----- Sezione: dettagli da archiviare ------------------------------------------------------
|
|
209
|
+
const renderArchiveList = (panel) => {
|
|
210
|
+
const isOpen = sectionsOpen.archiveList;
|
|
211
|
+
return (_jsxs("div", { style: { ...accordionStyles.accordion, ...accordionStyles.accordionInPanel }, children: [renderAccordionHeader({
|
|
212
|
+
section: 'archiveList',
|
|
213
|
+
isOpen,
|
|
214
|
+
tooltip: isOpen ? SDKUI_Localizator.HideDetailsToArchive : SDKUI_Localizator.ShowDetailsToArchive,
|
|
215
|
+
count: currentRows.length,
|
|
216
|
+
title: (_jsxs(_Fragment, { children: [_jsx(IconArchive, { fontSize: 15 }), _jsx("span", { style: multiDetailStyles.stepTypeLabelText, children: SDKUI_Localizator.DetailsToArchive })] })),
|
|
217
|
+
panel,
|
|
218
|
+
onToggleOpen: setSectionOpen,
|
|
219
|
+
}), isOpen && (_jsxs("div", { style: { ...styles.gridWrapper, ...(panel.isMaximized ? {} : { borderTop: `1px solid ${TMColors.card_background}` }) }, children: [_jsx(TMDataGrid, { dataColumns: gridColumns, dataSource: currentRows, keyExpr: "id", height: "100%", showSearchPanel: showGridSearch, showGroupPanel: false, showFilterPanel: false, showHeaderFilter: true, selection: gridSelection, selectedRowKeys: selectedRowKeys, onSelectionChanged: handleSelectionChanged, focusedRowKey: focusedRowKey, onFocusedRowChanged: handleFocusedRowChanged, onCellDblClick: handleCellDblClick, editing: gridEditing, onRowUpdating: handleRowUpdating, customContextMenuItems: contextMenuItems }), _jsx("button", { type: "button", onClick: openAddForm, style: styles.fab, ...hoverStyle({ backgroundColor: '#D94A9F', transform: 'scale(1.1)', boxShadow: '0 4px 12px rgba(37, 89, 165, 0.6)' }, { backgroundColor: TMColors.button_floating_background, transform: 'scale(1)', boxShadow: '0 2px 6px rgba(0,0,0,0.2)' }), children: _jsx(TMTooltip, { content: SDKUI_Localizator.Add, children: _jsx("i", { className: "dx-icon-add", style: { fontSize: '22px' } }) }) })] }))] }));
|
|
220
|
+
};
|
|
221
|
+
// ----- Pannelli del riepilogo, uno per sezione ----------------------------------------------
|
|
222
|
+
const renderSectionsInPanels = () => {
|
|
223
|
+
const definitions = [
|
|
224
|
+
{ section: 'masterInfo', name: `Master: ${getDtdDisplayName(dtd)}`, icon: _jsx(IconInfo, { fontSize: 22 }), count: masterFieldsCount, render: renderMasterInfo },
|
|
225
|
+
...(selectedRelation?.detailTID !== undefined
|
|
226
|
+
? [{ section: 'archivedDetails', name: SDKUI_Localizator.ArchivedDetails, icon: _jsx(IconSearchCheck, { fontSize: 22 }), count: archivedDetailsCount, render: renderArchivedDetails }]
|
|
227
|
+
: []),
|
|
228
|
+
{ section: 'archiveList', name: SDKUI_Localizator.DetailsToArchive, icon: _jsx(IconArchive, { fontSize: 22 }), count: currentRows.length, render: renderArchiveList },
|
|
229
|
+
];
|
|
230
|
+
const panels = definitions.map((definition, index) => ({
|
|
231
|
+
id: definition.section,
|
|
232
|
+
name: definition.name,
|
|
233
|
+
currentGroupDirection: 'vertical',
|
|
234
|
+
contentOptions: {
|
|
235
|
+
// Ingrandire una sezione collassata la apre: altrimenti il pannello a tutto schermo sarebbe vuoto
|
|
236
|
+
component: _jsx(TMSummarySectionSlot, { section: definition.section, render: definition.render, onBeforeMaximize: (section) => setSectionOpen(section, true) }),
|
|
237
|
+
// Una sezione chiusa vale 0% di altezza: è questo minimo a tenerne a schermo la testata
|
|
238
|
+
minHeight: `${SECTION_HEADER_HEIGHT_PX}px`,
|
|
239
|
+
// La sezione collassata è alta quanto la sua testata: i separatori non la ingrandiscono
|
|
240
|
+
isCollapsed: !sectionsOpen[definition.section],
|
|
241
|
+
},
|
|
242
|
+
// Barra dei pannelli: su mobile è l'unico modo per passare da una sezione all'altra
|
|
243
|
+
toolbarOptions: { icon: definition.icon, visible: true, isActive: true, orderNumber: index + 1, count: definition.count, tooltip: definition.name },
|
|
244
|
+
}));
|
|
245
|
+
const sections = panels.map(panel => panel.id);
|
|
246
|
+
// Le altezze salvate sono il punto di partenza, ma è il collasso corrente a decidere le quote
|
|
247
|
+
const savedStates = getMultiDetailPanelStates();
|
|
248
|
+
const savedDimensions = hasMultiDetailPanelStates()
|
|
249
|
+
? sections.reduce((acc, section) => {
|
|
250
|
+
if (savedStates[section])
|
|
251
|
+
acc[section] = { width: savedStates[section].width, height: savedStates[section].height };
|
|
252
|
+
return acc;
|
|
253
|
+
}, {})
|
|
254
|
+
: undefined;
|
|
255
|
+
// Con un pannello alla volta non ci sono quote da spartire: quello a schermo prende tutta l'altezza.
|
|
256
|
+
// Le quote proporzionali (e il layout salvato) valgono solo per i pannelli impilati
|
|
257
|
+
const fullHeights = sections.reduce((acc, section) => { acc[section] = { width: '100%', height: '100%' }; return acc; }, {});
|
|
258
|
+
const initialDimensions = isMobile ? fullHeights : sectionPanelHeights(sections, sectionsOpen, savedDimensions);
|
|
259
|
+
const initialVisibility = sections.reduce((acc, section) => { acc[section] = isMobile ? section === MOBILE_SECTION : true; return acc; }, {});
|
|
260
|
+
return (_jsx("div", { style: styles.panelsHost, children: _jsx("div", { style: styles.panelsHostFill, children: _jsxs(TMPanelManagerWithPersistenceProvider
|
|
261
|
+
// Le dimensioni sono lette solo al montaggio: dopo la cancellazione del layout, e al
|
|
262
|
+
// passaggio fra impilato e un pannello alla volta, i pannelli vanno rimontati
|
|
263
|
+
, { panels: panels, initialVisibility: initialVisibility, defaultDimensions: initialDimensions, initialDimensions: initialDimensions, initialMobilePanelId: MOBILE_SECTION,
|
|
264
|
+
// Su mobile il layout è imposto dal dispositivo: salvarlo sovrascriverebbe quello dell'utente
|
|
265
|
+
isPersistenceEnabled: !isMobile,
|
|
266
|
+
// Le altezze si salvano solo dopo che l'utente ha spostato un separatore (vedi TMSummaryResizeTracker)
|
|
267
|
+
persistPanelStates: !isMobile ? persistPanelStatesOnUserResize : undefined, children: [_jsx(TMSummaryResizeTracker, { onUserResize: () => { hasUserResizedRef.current = true; } }), _jsx(TMSectionPanelsHeights, { sections: sections, sectionsOpen: sectionsOpen }), _jsx(TMPanelManagerContainer, { panels: panels, direction: 'vertical', showToolbar: isMobile, minPanelSizePx: SECTION_HEADER_HEIGHT_PX, gutterSizePx: isMobile ? undefined : PANEL_GUTTER_PX })] }, `${layoutResetToken}-${isMobile}`) }) }));
|
|
268
|
+
};
|
|
269
|
+
const renderArchiveSummary = () => (_jsxs("div", { style: styles.summaryContainer, children: [renderSectionsInPanels(), _jsxs("div", { style: styles.footer, children: [_jsxs("label", { style: styles.footerLabel, ...hoverStyle({ borderColor: TMColors.primary, color: TMColors.text_normal }, { borderColor: TMColors.card_background, color: TMColors.label_normal }), children: [_jsx("input", { type: "checkbox", checked: stopOnFirstError, onChange: (e) => setStopOnFirstError(e.target.checked), style: styles.checkbox }), SDKUI_Localizator.StopOnFirstError] }), _jsxs("button", { type: "button", onClick: archiveAllAsync, disabled: isArchiveDisabled, style: {
|
|
270
|
+
...styles.archiveButton,
|
|
271
|
+
background: isArchiveDisabled ? TMColors.disabled : TMColors.success,
|
|
272
|
+
boxShadow: isArchiveDisabled ? 'none' : `0 4px 14px ${TMColors.success}55`,
|
|
273
|
+
cursor: isArchiveDisabled ? 'default' : 'pointer',
|
|
274
|
+
opacity: isArchiveDisabled ? 0.6 : 1,
|
|
275
|
+
}, ...(isArchiveDisabled ? {} : hoverStyle({ transform: 'translateY(-2px)', boxShadow: `0 6px 20px ${TMColors.success}77`, filter: 'brightness(1.06)' }, { transform: 'translateY(0)', boxShadow: `0 4px 14px ${TMColors.success}55`, filter: 'brightness(1)' })), children: [_jsx(IconArchive, {}), archiveButtonCaption] })] })] }));
|
|
276
|
+
// ----- Render principale --------------------------------------------------------------------
|
|
277
|
+
if (isLoading)
|
|
278
|
+
return null;
|
|
279
|
+
return _jsxs(_Fragment, { children: [_jsx(TMLayoutWaitingContainer, { direction: 'vertical', ...waitPanel, isCancelable: true, abortController: abortController, usePortal: true, children: _jsx(TMModal, { width: isSummaryPhase ? '95%' : '720px', height: isSummaryPhase ? '95%' : 'auto', onClose: closeModal, title: modalTitle, hidePopup: false, askClosingConfirm: archiveRows.length > 0, recenterOnResize: true, titleActions: renderOptionsMenu(), children: _jsxs("div", { style: styles.content, children: [hasMultipleTypes && _jsx("div", { style: styles.header, children: renderStepper({
|
|
280
|
+
steps,
|
|
281
|
+
phase,
|
|
282
|
+
hasMultipleTypes,
|
|
283
|
+
isBackLocked,
|
|
284
|
+
showBackArrow: isSummaryPhase,
|
|
285
|
+
onBack: backToTypeSelection,
|
|
286
|
+
onStepClick: (stepPhase) => (stepPhase === MultiDetailArchivePhase.SelectDcmtType ? backToTypeSelection() : setPhase(stepPhase)),
|
|
287
|
+
}) }), !isSummaryPhase
|
|
288
|
+
? renderSelectDcmtType({ detailRelationItems, selectedRelation, onSelectRelation: selectRelation })
|
|
289
|
+
: (isSummaryReady
|
|
290
|
+
? renderArchiveSummary()
|
|
291
|
+
: _jsx("div", { style: styles.loader, children: _jsx(LoadIndicator, { height: 40, width: 40 }) }))] }) }) }), isOpenAddForm && selectedRelation?.detailTID && (_jsx(TMDcmtForm, { isModal: true, titleModal: getDtdDisplayName(selectedItem?.detailDtd), TID: selectedRelation.detailTID, layoutMode: LayoutModes.Ark, showBackButton: false, allowButtonsRefs: false, inputMids: formInputMids, inputFile: editingRow?.__file ?? null, archiveListMode: {
|
|
292
|
+
isEditingRow: editingRowId !== undefined,
|
|
293
|
+
onUpsertRow: (values, file) => upsertRow(values, file),
|
|
294
|
+
}, onClose: closeAddForm, allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback, editTaskCallback: editTaskCallback, handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers, showDcmtFormSidebar: showDcmtFormSidebar, showTodoDcmtForm: showTodoDcmtForm, openFileUploaderPdfEditor: openFileUploaderPdfEditor, graphometricManager: graphometricManager })), isOpenMasterForm && masterDcmt?.TID !== undefined && masterDcmt?.DID !== undefined && (_jsx(TMDcmtForm, { isModal: true, titleModal: `${SDKUI_Localizator.Update}: ${getDtdDisplayName(dtd)}`, TID: masterDcmt.TID, DID: masterDcmt.DID, layoutMode: LayoutModes.Update, showBackButton: false, allowRelations: false, allowButtonsRefs: false, onSavedAsyncCallback: handleMasterSavedAsync, onClose: () => setIsOpenMasterForm(false), allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback, editTaskCallback: editTaskCallback, onTaskCreateRequest: onTaskCreateRequest, handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers, showDcmtFormSidebar: showDcmtFormSidebar, showTodoDcmtForm: showTodoDcmtForm, openFileUploaderPdfEditor: openFileUploaderPdfEditor, graphometricManager: graphometricManager, editPdfForm: editPdfForm, openS4TViewer: openS4TViewer, fetchRemoteCertificates: fetchRemoteCertificates, onOpenS4TViewerRequest: onOpenS4TViewerRequest, onOpenPdfEditorRequest: onOpenPdfEditorRequest, onReferenceClick: onReferenceClick }))] });
|
|
295
|
+
};
|
|
296
|
+
export default TMMultiMasterDetailDcmtsForm;
|