@topconsultnpm/sdkui-react 6.22.0-t1 → 6.22.0-t3
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 +3 -3
- package/lib/components/NewComponents/ContextMenu/hooks.d.ts +1 -1
- package/lib/components/NewComponents/ContextMenu/styles.d.ts +45 -43
- package/lib/components/NewComponents/FloatingMenuBar/TMFloatingMenuBar.js +6 -6
- package/lib/components/NewComponents/FloatingMenuBar/styles.d.ts +80 -73
- package/lib/components/base/Styled.d.ts +92 -76
- package/lib/components/base/Styled.js +7 -5
- package/lib/components/base/TMAccordionNew.js +7 -7
- package/lib/components/base/TMAlert.d.ts +32 -32
- package/lib/components/base/TMAlert.js +6 -8
- package/lib/components/base/TMAreaManager.js +53 -55
- package/lib/components/base/TMButton.d.ts +13 -0
- package/lib/components/base/TMButton.js +139 -7
- package/lib/components/base/TMClosableList.js +3 -3
- package/lib/components/base/TMCustomButton.js +40 -48
- package/lib/components/base/TMDataGrid.d.ts +4 -0
- package/lib/components/base/TMDataGrid.js +292 -12
- package/lib/components/base/TMDataGridExportForm.js +39 -30
- package/lib/components/base/TMDropDownMenu.js +1 -1
- package/lib/components/base/TMEditorBase.d.ts +2 -0
- package/lib/components/base/TMFileManager.js +5 -3
- package/lib/components/base/TMFileManagerDataGridView.js +12 -3
- package/lib/components/base/TMFileManagerThumbnailItems.js +20 -10
- package/lib/components/base/TMFileManagerUtils.d.ts +6 -6
- package/lib/components/base/TMFileManagerUtils.js +37 -1
- package/lib/components/base/TMLayout.d.ts +2 -2
- package/lib/components/base/TMLayout.js +3 -3
- package/lib/components/base/TMList.js +1 -1
- package/lib/components/base/TMListView.js +3 -3
- 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 +141 -28
- package/lib/components/base/TMPopUp.js +5 -2
- package/lib/components/base/TMResizableMenu.js +2 -2
- package/lib/components/base/TMRightSidebar.js +1 -1
- package/lib/components/base/TMShowAllOrMaxItemsButton.js +1 -1
- package/lib/components/base/TMSpinner.d.ts +2 -1
- package/lib/components/base/TMSpinner.js +9 -7
- package/lib/components/base/TMTab.js +2 -2
- package/lib/components/base/TMTabControl.d.ts +106 -0
- package/lib/components/base/TMTabControl.js +664 -0
- package/lib/components/base/TMToggleButton.js +2 -2
- package/lib/components/base/TMToolbarCard.js +3 -3
- package/lib/components/base/TMTooltip.d.ts +2 -1
- package/lib/components/base/TMTooltip.js +24 -8
- package/lib/components/base/TMTreeView.d.ts +13 -7
- package/lib/components/base/TMTreeView.js +143 -70
- package/lib/components/base/TMWaitPanel.js +3 -3
- package/lib/components/base/waitPanel/TMWaitPanelConfirm.d.ts +12 -0
- package/lib/components/base/waitPanel/TMWaitPanelConfirm.js +185 -0
- package/lib/components/base/waitPanel/TMWaitPanelManager.d.ts +169 -0
- package/lib/components/base/waitPanel/TMWaitPanelManager.js +320 -0
- package/lib/components/base/waitPanel/TMWaitPanelView.d.ts +53 -0
- package/lib/components/base/waitPanel/TMWaitPanelView.js +274 -0
- package/lib/components/base/waitPanel/index.d.ts +1 -0
- package/lib/components/base/waitPanel/index.js +1 -0
- package/lib/components/choosers/TMCultureIDPicker.js +2 -2
- package/lib/components/choosers/TMDataListItemChooser.js +1 -1
- package/lib/components/choosers/TMDataListItemPicker.js +2 -2
- package/lib/components/choosers/TMDcmtTypeChooser.js +5 -4
- package/lib/components/choosers/TMDiskChooser.js +1 -1
- package/lib/components/choosers/TMDistinctValues.d.ts +9 -7
- package/lib/components/choosers/TMDistinctValues.js +157 -141
- package/lib/components/choosers/TMDynDataListItemChooser.js +1 -1
- package/lib/components/choosers/TMImageIDChooser.js +1 -1
- package/lib/components/choosers/TMMetadataChooser.js +3 -3
- package/lib/components/choosers/TMPathChooser.js +17 -34
- package/lib/components/choosers/TMQuickSearchInfo.d.ts +13 -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/TMRelationChooser.js +1 -1
- package/lib/components/choosers/TMSelectedValuesSummary.d.ts +13 -0
- package/lib/components/choosers/TMSelectedValuesSummary.js +89 -0
- package/lib/components/choosers/TMUserChooser.js +1 -1
- package/lib/components/editors/TMCheckBox.js +1 -1
- package/lib/components/editors/TMDateBox.d.ts +16 -1
- package/lib/components/editors/TMDateBox.js +90 -22
- package/lib/components/editors/TMDropDown.d.ts +3 -0
- package/lib/components/editors/TMDropDown.js +197 -5
- package/lib/components/editors/TMEditorStyled.d.ts +21 -43
- package/lib/components/editors/TMFormulaEditor.js +1 -1
- package/lib/components/editors/TMHtmlContentDisplay.js +1 -1
- package/lib/components/editors/TMLocalizedTextBox.js +1 -1
- package/lib/components/editors/TMMetadataEditor.d.ts +5 -1
- package/lib/components/editors/TMMetadataEditor.js +27 -23
- package/lib/components/editors/TMMetadataValues.js +6 -6
- package/lib/components/editors/TMRadioButton.js +2 -2
- package/lib/components/editors/TMSummary.js +3 -3
- package/lib/components/editors/TMTextArea.d.ts +1 -0
- package/lib/components/editors/TMTextArea.js +25 -17
- package/lib/components/editors/TMTextBox.d.ts +2 -0
- package/lib/components/editors/TMTextBox.js +32 -21
- package/lib/components/editors/TMTextExpression.js +1 -1
- package/lib/components/features/archive/TMArchive.js +24 -5
- package/lib/components/features/assistant/TMHelpOnLineChat.d.ts +29 -0
- package/lib/components/features/assistant/TMHelpOnLineChat.js +1384 -0
- package/lib/components/features/assistant/TMToppyDraggableHelpCenter.js +4 -4
- package/lib/components/features/assistant/TMToppySpeechBubble.js +1 -1
- package/lib/components/features/assistant/dataset/Designer-Suggested-Questions.json +102 -0
- package/lib/components/features/assistant/dataset/Login-Suggested-Questions.json +32 -0
- package/lib/components/features/assistant/dataset/Surfer-Suggested-Questions.json +102 -0
- package/lib/components/features/documents/TMBatchUpdateForm.js +22 -9
- package/lib/components/features/documents/TMCopyToFolderForm.js +50 -42
- 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 +281 -113
- package/lib/components/features/documents/TMDcmtFormActionButtons.d.ts +11 -0
- package/lib/components/features/documents/TMDcmtFormActionButtons.js +79 -9
- package/lib/components/features/documents/TMDcmtIcon.d.ts +1 -3
- package/lib/components/features/documents/TMDcmtIcon.js +8 -8
- package/lib/components/features/documents/TMDcmtPreview.d.ts +7 -5
- package/lib/components/features/documents/TMDcmtPreview.js +16 -10
- package/lib/components/features/documents/TMDcmtTasks.js +2 -9
- package/lib/components/features/documents/TMDownloadRelationViewerSection.js +1 -1
- package/lib/components/features/documents/TMFileUploader.js +7 -7
- package/lib/components/features/documents/TMMasterDetailDcmts.d.ts +2 -0
- package/lib/components/features/documents/TMMasterDetailDcmts.js +95 -108
- package/lib/components/features/documents/TMMasterInfoFields.d.ts +20 -0
- package/lib/components/features/documents/TMMasterInfoFields.js +185 -0
- package/lib/components/features/documents/TMMergeToPdfForm.d.ts +1 -2
- package/lib/components/features/documents/TMMergeToPdfForm.js +83 -56
- package/lib/components/features/documents/TMMultiMasterDetailDcmtsForm.d.ts +46 -0
- package/lib/components/features/documents/TMMultiMasterDetailDcmtsForm.js +320 -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 +29 -9
- package/lib/components/features/documents/TMRelationViewer.js +310 -208
- package/lib/components/features/documents/copyAndMergeDcmtsShared.d.ts +1 -1
- package/lib/components/features/documents/relationTreeState.d.ts +32 -0
- package/lib/components/features/documents/relationTreeState.js +89 -0
- package/lib/components/features/search/TMMetadataOutputForm.js +1 -1
- package/lib/components/features/search/TMMetadataSorterForm.js +1 -1
- package/lib/components/features/search/TMSavedQuerySelector.js +2 -2
- package/lib/components/features/search/TMSearch.d.ts +1 -1
- package/lib/components/features/search/TMSearch.js +172 -34
- package/lib/components/features/search/TMSearchQueryEditor.js +7 -5
- package/lib/components/features/search/TMSearchQueryPanel.d.ts +14 -4
- package/lib/components/features/search/TMSearchQueryPanel.js +153 -62
- package/lib/components/features/search/TMSearchResult.d.ts +21 -0
- package/lib/components/features/search/TMSearchResult.js +461 -152
- package/lib/components/features/search/TMSignatureInfoContent.js +1 -1
- package/lib/components/features/search/TMTreeSelector.js +130 -83
- package/lib/components/features/search/TMViewHistoryDcmt.js +14 -25
- package/lib/components/features/tasks/TMTaskForm.js +1 -1
- package/lib/components/features/tasks/TMTaskFormUtils.js +3 -3
- package/lib/components/features/tasks/TMTasksAgenda.js +1 -1
- package/lib/components/features/tasks/TMTasksCalendar.js +1 -1
- package/lib/components/features/tasks/TMTasksHeader.js +1 -1
- package/lib/components/features/tasks/TMTasksUtilsView.js +1 -1
- package/lib/components/features/tasks/TMTasksView.js +97 -102
- package/lib/components/features/wg/TMWGsCopyMoveForm.js +92 -92
- package/lib/components/features/workflow/TMWorkflowPopup.d.ts +10 -0
- package/lib/components/features/workflow/TMWorkflowPopup.js +9 -5
- package/lib/components/features/workflow/diagram/ConnectionComponent.js +3 -3
- package/lib/components/features/workflow/diagram/DiagramItemComponent.js +3 -3
- package/lib/components/features/workflow/diagram/DiagramItemForm.js +1 -1
- package/lib/components/features/workflow/diagram/DiagramItemSvgContent.js +1 -1
- package/lib/components/features/workflow/diagram/RecipientList.js +1 -1
- package/lib/components/features/workflow/diagram/WFDiagram.js +4 -4
- package/lib/components/features/workflow/diagram/WorkitemRecipientsEditor.d.ts +3 -1
- package/lib/components/forms/Login/ChangePasswordInputs.d.ts +3 -1
- package/lib/components/forms/Login/Menu.js +1 -1
- package/lib/components/forms/Login/OTPReader.js +1 -1
- package/lib/components/forms/Login/PasswordStrengthChecker.js +1 -1
- package/lib/components/forms/Login/RapidAccessLogin.js +2 -2
- package/lib/components/forms/Login/RecoverPasswordFlow.js +2 -2
- package/lib/components/forms/Login/SelectBox.js +1 -1
- package/lib/components/forms/Login/StepIndicator.js +1 -1
- package/lib/components/forms/Login/TMLoginForm.js +7 -7
- package/lib/components/forms/Login/TextBox.js +1 -1
- package/lib/components/forms/TMApplyForm.js +3 -3
- package/lib/components/forms/TMChooserForm.js +1 -1
- package/lib/components/forms/TMResultDialog.js +1 -1
- package/lib/components/forms/TMSaveForm.js +3 -3
- package/lib/components/grids/TMBlogAttachments.js +14 -3
- package/lib/components/grids/TMBlogHeader.js +5 -1
- package/lib/components/grids/TMBlogsPost.d.ts +2 -0
- package/lib/components/grids/TMBlogsPost.js +122 -99
- package/lib/components/grids/TMBlogsPostUtils.d.ts +1 -0
- package/lib/components/grids/TMBlogsPostUtils.js +15 -4
- package/lib/components/grids/TMRecentsManager.js +4 -4
- package/lib/components/grids/TMValidationItemsList.js +1 -1
- package/lib/components/index.d.ts +6 -0
- package/lib/components/index.js +5 -0
- package/lib/components/layout/panelManager/TMPanelManagerContainer.d.ts +1 -0
- package/lib/components/layout/panelManager/TMPanelManagerContainer.js +25 -15
- package/lib/components/layout/panelManager/TMPanelManagerContext.js +68 -93
- package/lib/components/layout/panelManager/TMPanelManagerToolbar.d.ts +4 -5
- package/lib/components/layout/panelManager/TMPanelManagerToolbar.js +1 -1
- package/lib/components/layout/panelManager/TMPanelWrapper.js +3 -3
- package/lib/components/layout/panelManager/types.d.ts +3 -0
- package/lib/components/layout/panelManager/utils.js +13 -11
- package/lib/components/pages/TMPage.js +30 -32
- package/lib/components/query/TMQueryCountButton.js +1 -1
- package/lib/components/query/TMQueryEditor.d.ts +17 -10
- package/lib/components/query/TMQueryEditor.js +9 -8
- package/lib/components/sidebar/TMCommandsPanel.d.ts +4 -4
- package/lib/components/sidebar/TMCommandsPanel.js +1 -1
- package/lib/components/sidebar/TMHeader.d.ts +1 -0
- package/lib/components/sidebar/TMHeader.js +37 -27
- package/lib/components/sidebar/TMSidebar.js +1 -1
- package/lib/components/sidebar/TMSidebarItem.js +1 -1
- package/lib/components/viewers/TMMidViewer.js +6 -3
- package/lib/components/viewers/TMTidViewer.js +89 -28
- package/lib/components/wizard/TMStepIndicator.js +3 -3
- package/lib/css/tm-sdkui.css +1 -1
- package/lib/devextreme-license.d.ts +1 -0
- package/lib/devextreme-license.js +3 -0
- package/lib/helper/Enum_Localizator.d.ts +4 -4
- package/lib/helper/Enum_Localizator.js +1 -0
- package/lib/helper/Globalization.d.ts +1 -1
- package/lib/helper/SDKUI_Globals.d.ts +110 -0
- package/lib/helper/SDKUI_Globals.js +151 -0
- package/lib/helper/SDKUI_Localizator.d.ts +756 -677
- package/lib/helper/SDKUI_Localizator.js +790 -0
- package/lib/helper/TMAppUpdatedModal.d.ts +2 -0
- package/lib/helper/TMAppUpdatedModal.js +134 -0
- package/lib/helper/TMIcons.d.ts +1 -0
- package/lib/helper/TMIcons.js +4 -3
- package/lib/helper/TMPdfViewer.js +1 -1
- package/lib/helper/TMToppyMessage.js +1 -1
- package/lib/helper/TMUtils.d.ts +51 -4
- package/lib/helper/TMUtils.js +273 -12
- package/lib/helper/ZipManager.d.ts +1 -1
- package/lib/helper/ZipManager.js +2 -1
- package/lib/helper/checkinCheckoutManager.d.ts +1 -1
- package/lib/helper/checkinCheckoutManager.js +1 -1
- package/lib/helper/dataGridSearchHelper.d.ts +28 -0
- package/lib/helper/dataGridSearchHelper.js +51 -0
- package/lib/helper/dcmtsHelper.d.ts +22 -0
- package/lib/helper/dcmtsHelper.js +60 -1
- package/lib/helper/helpers.d.ts +24 -2
- package/lib/helper/helpers.js +59 -3
- 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/useCheckInOutOperations.d.ts +0 -6
- package/lib/hooks/useCheckInOutOperations.js +14 -34
- package/lib/hooks/useDataUserIdItem.d.ts +1 -0
- package/lib/hooks/useDataUserIdItem.js +1 -0
- package/lib/hooks/useDcmtOperations.d.ts +3 -12
- package/lib/hooks/useDcmtOperations.js +187 -179
- package/lib/hooks/useDocumentOperations.d.ts +5 -0
- package/lib/hooks/useDocumentOperations.js +64 -33
- package/lib/hooks/useInputDialog.js +1 -1
- package/lib/hooks/useMultiMasterDetailDcmts.d.ts +98 -0
- package/lib/hooks/useMultiMasterDetailDcmts.js +758 -0
- package/lib/hooks/usePreventFileDrop.js +9 -0
- package/lib/hooks/useQueryParametersDialog.js +1 -1
- 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/hooks/useWorkflowApprove.js +33 -17
- package/lib/index.d.ts +2 -0
- package/lib/index.js +5 -2
- package/lib/services/caseflow/CaseFlowService.d.ts +277 -0
- package/lib/services/caseflow/CaseFlowService.js +761 -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 +4 -4
- package/package.json +16 -13
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import React, { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from 'react';
|
|
3
3
|
import styled from 'styled-components';
|
|
4
4
|
import { LoadIndicator } from 'devextreme-react';
|
|
5
|
-
import { AppModules, DataColumnTypes, DataListViewModes, DcmtTypeListCacheService, LayoutCacheService, LayoutModes, MetadataDataDomains,
|
|
6
|
-
import { deepCompare, generateUniqueColumnKeys, genUniqueId, getSearchToolbarVisibility, IconAll, IconBoard, IconDcmtTypeSys, IconDelete, IconMenuVertical, IconPlatform, IconRefresh, IconSearchCheck, IconShow, isApprovalWorkflowView, isSign4TopEnabled, searchResultDescriptorToSimpleArray, searchResultToMetadataValues, SDKUI_Globals, SDKUI_Localizator } from '../../../helper';
|
|
5
|
+
import { AppModules, DataColumnTypes, DataListViewModes, DcmtTypeListCacheService, LayoutCacheService, LayoutModes, MetadataDataDomains, SDK_Globals, SystemMIDsAsNumber, UserListCacheService, } from '@topconsultnpm/sdk-ts';
|
|
6
|
+
import { customizeSearchByDisplayText, deepCompare, formatDateTimeByMetadataFormat, formatNumberByMetadataFormat, generateUniqueColumnKeys, genUniqueId, getColumnFormatInfo, getDateDisplayText, getNumberDisplayText, getSearchToolbarVisibility, IconAll, IconBoard, IconDcmtTypeSys, IconDelete, IconDuplicate, IconEdit, IconMenuVertical, IconPlatform, IconRefresh, IconSearchCheck, IconShow, isApprovalWorkflowView, isSign4TopEnabled, searchResultDescriptorToSimpleArray, searchResultToMetadataValues, SDKUI_Globals, SDKUI_Localizator, IconCloseOutline, getSearchResultPanelLayout, getSearchResultPanelLayoutSignature, hasSearchResultPanelLayout, saveSearchResultPanelLayout, subscribeSearchResultPanelLayout } from '../../../helper';
|
|
7
7
|
import { CounterItemKey } from '../../base/TMCounterContainer';
|
|
8
8
|
import { getDcmtCicoStatus } from '../../../helper/checkinCheckoutManager';
|
|
9
9
|
import { DcmtOperationTypes, SearchResultContext, } from '../../../ts';
|
|
10
|
-
import { Gutters } from '../../../utils/theme';
|
|
10
|
+
import { Gutters, TMColors } from '../../../utils/theme';
|
|
11
11
|
import { useDataListItem } from '../../../hooks/useDataListItem';
|
|
12
12
|
import { useDataUserIdItem } from '../../../hooks/useDataUserIdItem';
|
|
13
13
|
import { getSelectedDcmtsOrFocused, useDocumentOperations } from '../../../hooks/useDocumentOperations';
|
|
@@ -16,14 +16,14 @@ import TMAccordionNew from '../../base/TMAccordionNew';
|
|
|
16
16
|
import TMButton from '../../base/TMButton';
|
|
17
17
|
import TMDataGrid, { TMDataGridPageSize } from '../../base/TMDataGrid';
|
|
18
18
|
import { DeviceType, useDeviceType } from '../../base/TMDeviceProvider';
|
|
19
|
-
import { TMLayoutItem, TMSplitterLayout } from '../../base/TMLayout';
|
|
19
|
+
import TMLayoutContainer, { TMLayoutItem, TMSplitterLayout } from '../../base/TMLayout';
|
|
20
20
|
import { ButtonNames, TMExceptionBoxManager, TMMessageBoxManager } from '../../base/TMPopUp';
|
|
21
21
|
import TMSpinner from '../../base/TMSpinner';
|
|
22
22
|
import { StyledMultiViewPanel } from '../../base/Styled';
|
|
23
|
-
import { TMLayoutWaitingContainer } from '../../base/TMWaitPanel';
|
|
24
23
|
import TMMetadataValues from '../../editors/TMMetadataValues';
|
|
25
24
|
import TMTidViewer from '../../viewers/TMTidViewer';
|
|
26
|
-
import {
|
|
25
|
+
import { useTMPanelManagerContext } from '../../layout/panelManager/TMPanelManagerContext';
|
|
26
|
+
import { TMPanelManagerWithPersistenceProvider } from '../../layout/panelManager/TMPanelManagerWithPersistenceProvider';
|
|
27
27
|
import TMPanelManagerContainer from '../../layout/panelManager/TMPanelManagerContainer';
|
|
28
28
|
import TMContextMenu from '../../NewComponents/ContextMenu/TMContextMenu';
|
|
29
29
|
import TMToppyDraggableHelpCenter from '../assistant/TMToppyDraggableHelpCenter';
|
|
@@ -33,7 +33,6 @@ import TMDcmtPreview from '../documents/TMDcmtPreview';
|
|
|
33
33
|
import { WorkFlowOperationButtons } from '../workflow/TMWorkflowPopup';
|
|
34
34
|
// Local
|
|
35
35
|
import TMSearchResultFloatingActionButton from './TMSearchResultFloatingActionButton';
|
|
36
|
-
let abortControllerLocal = new AbortController();
|
|
37
36
|
//#region Helper Methods
|
|
38
37
|
export const getSearchResultCountersSingleCategory = (searchResults) => {
|
|
39
38
|
// let totDcmtTypes = searchResults.length;
|
|
@@ -51,13 +50,25 @@ const orderByName = (array) => {
|
|
|
51
50
|
return 1;
|
|
52
51
|
} return 0; });
|
|
53
52
|
};
|
|
53
|
+
//#endregion Helper Methods
|
|
54
|
+
/**
|
|
55
|
+
* Contesti che ricordano il layout dei pannelli, condividendone uno solo.
|
|
56
|
+
* Gli altri sono esclusi di proposito: FREE_SEARCH ha un pannello in più, quindi il suo layout non vale
|
|
57
|
+
* per gli altri, e i restanti mostrano il risultato dentro contenitori con esigenze di spazio loro.
|
|
58
|
+
*/
|
|
59
|
+
const PERSISTED_LAYOUT_CONTEXTS = [
|
|
60
|
+
SearchResultContext.METADATA_SEARCH,
|
|
61
|
+
SearchResultContext.WORKFLOW_APPROVE,
|
|
62
|
+
];
|
|
54
63
|
const TMSearchResult = ({
|
|
55
64
|
// Data
|
|
56
65
|
groupId, searchResults = [], context = SearchResultContext.METADATA_SEARCH, title, selectedSearchResultTID, floatingActionConfig, workingGroupContext = undefined, inputDID,
|
|
57
66
|
// Boolean flags to enable/disable features
|
|
58
|
-
autoFocusFirstRow = true, formAutoOpen, isVisible = true, allowRelations = true, openDcmtFormAsModal = false, showSearchResultSidebar = true, showDcmtFormSidebar = true, showSelector = false, isClosable = false, allowFloatingBar = true, showToolbarHeader = true, showBackButton = true, disableAccordionIfSingleCategory = false, editPdfForm = false, openS4TViewer = false, showTodoDcmtForm = false, showToppyDraggableHelpCenter = true, toppyHelpCenterUsePortal = false, showNoDcmtFoundMessage = true, enablePinIcons = true,
|
|
67
|
+
autoFocusFirstRow = true, formAutoOpen, isVisible = true, allowRelations = true, openDcmtFormAsModal = false, showSearchResultSidebar = true, showDcmtFormSidebar = true, showSelector = false, isClosable = false, allowFloatingBar = true, showToolbarHeader = true, showBackButton = true, backCaption, showToolbarCloseButton = false, disableAccordionIfSingleCategory = false, editPdfForm = false, openS4TViewer = false, showTodoDcmtForm = false, showToppyDraggableHelpCenter = true, toppyHelpCenterUsePortal = false, showNoDcmtFoundMessage = true, enablePinIcons = true, showCounterConfig = true, showActionsColumn = false, compactPager = false, onRowDuplicateRequest,
|
|
68
|
+
// Counters
|
|
69
|
+
counterConfig,
|
|
59
70
|
// Callbacks (optional)
|
|
60
|
-
openInOffice, onRefreshAfterAddDcmtToFavs, onRefreshSearchAsyncDatagrid, onSelectedTIDChanged, onWFOperationCompleted, onClose, onFileOpened, onTaskCreateRequest, openWGsCopyMoveForm, openCommentFormCallback, openAddDocumentForm, onOpenS4TViewerRequest, onOpenPdfEditorRequest, openFileUploaderPdfEditor, passToArchiveCallback, onReferenceClick,
|
|
71
|
+
openInOffice, onRefreshAfterAddDcmtToFavs, onRefreshSearchAsyncDatagrid, onSelectedTIDChanged, onSelectedTIDCleared, onWFOperationCompleted, onClose, onFileOpened, onTaskCreateRequest, openWGsCopyMoveForm, openCommentFormCallback, openAddDocumentForm, onOpenS4TViewerRequest, onOpenPdfEditorRequest, openFileUploaderPdfEditor, passToArchiveCallback, onReferenceClick,
|
|
61
72
|
// Tasks
|
|
62
73
|
allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTaskCallback, editTaskCallback,
|
|
63
74
|
// Navigation
|
|
@@ -69,13 +80,19 @@ handleNavigateToWGs, handleNavigateToDossiers, fetchRemoteCertificates, graphome
|
|
|
69
80
|
// Quando l'utente seleziona manualmente, il ref viene settato a false e il focus automatico
|
|
70
81
|
// torna al comportamento normale.
|
|
71
82
|
const isFirstAutoFocusRef = useRef(true);
|
|
83
|
+
// Mostra il pannello lista. È una ref perché il TMPanelManagerProvider sta dentro al JSX di
|
|
84
|
+
// questo componente, quindi qui il context non si può usare: la riempie ShowMainPanelBridge.
|
|
85
|
+
const showMainPanelRef = useRef(null);
|
|
72
86
|
// ID state to force remount of components
|
|
73
87
|
const [id, setID] = useState('');
|
|
74
88
|
// Document type descriptor of the currently document
|
|
75
89
|
const [fromDTD, setFromDTD] = useState();
|
|
76
90
|
const [currentDcmt, setCurrentDcmt] = useState();
|
|
77
|
-
//
|
|
78
|
-
|
|
91
|
+
// Passo corrente. Su mobile decide anche quale pannello è a schermo (vedi isSteppedLayout).
|
|
92
|
+
// 'auto' -> l'utente non ha ancora scelto: si può selezionare il primo tipo documento
|
|
93
|
+
// 'selector' -> è tornato indietro col back: non selezionare niente al posto suo
|
|
94
|
+
// 'results' -> è sulla griglia del tipo scelto
|
|
95
|
+
const [navStep, setNavStep] = useState('auto');
|
|
79
96
|
// State to control the selected search result
|
|
80
97
|
const [selectedSearchResult, setSelectedSearchResult] = useState();
|
|
81
98
|
// State to control the search results to show in the datagrid
|
|
@@ -303,7 +320,16 @@ handleNavigateToWGs, handleNavigateToDossiers, fetchRemoteCertificates, graphome
|
|
|
303
320
|
createTaskFromDocumentOrWorkItem();
|
|
304
321
|
}
|
|
305
322
|
};
|
|
306
|
-
const
|
|
323
|
+
const handleRefreshClick = onRefreshSearchAsyncDatagrid ? async () => {
|
|
324
|
+
TMSpinner.show({ description: `${SDKUI_Localizator.UpdateInProgress}`, backgroundColor: 'transparent' });
|
|
325
|
+
try {
|
|
326
|
+
await onRefreshSearchAsyncDatagrid();
|
|
327
|
+
}
|
|
328
|
+
finally {
|
|
329
|
+
TMSpinner.hide();
|
|
330
|
+
}
|
|
331
|
+
} : undefined;
|
|
332
|
+
const { operationItems, selectedDcmtInfos, renderFloatingBar, renderDcmtOperations, features, } = useDocumentOperations({
|
|
307
333
|
context: context,
|
|
308
334
|
documentData: {
|
|
309
335
|
dtd: fromDTD,
|
|
@@ -316,7 +342,7 @@ handleNavigateToWGs, handleNavigateToDossiers, fetchRemoteCertificates, graphome
|
|
|
316
342
|
searchResult: selectedSearchResult,
|
|
317
343
|
datagridUtility: {
|
|
318
344
|
visibleItems,
|
|
319
|
-
onRefreshSearchAsyncDatagrid,
|
|
345
|
+
onRefreshSearchAsyncDatagrid: handleRefreshClick,
|
|
320
346
|
onRefreshDataRowsAsync,
|
|
321
347
|
refreshFocusedDataRowAsync,
|
|
322
348
|
onRefreshBlogDatagrid,
|
|
@@ -343,6 +369,7 @@ handleNavigateToWGs, handleNavigateToDossiers, fetchRemoteCertificates, graphome
|
|
|
343
369
|
allowRelations,
|
|
344
370
|
showTodoDcmtForm,
|
|
345
371
|
graphometricManager,
|
|
372
|
+
showSelector,
|
|
346
373
|
},
|
|
347
374
|
tasks: {
|
|
348
375
|
allTasks: allTasks,
|
|
@@ -377,9 +404,69 @@ handleNavigateToWGs, handleNavigateToDossiers, fetchRemoteCertificates, graphome
|
|
|
377
404
|
openTaskFormHandler,
|
|
378
405
|
},
|
|
379
406
|
});
|
|
380
|
-
const { isOpenDcmtForm, openFormHandler, dcmtFormLayoutMode, onDcmtFormOpenChange, showSearchTMDatagrid,
|
|
407
|
+
const { isOpenDcmtForm, isDcmtFormModal, openFormHandler, dcmtFormLayoutMode, onDcmtFormOpenChange, showSearchTMDatagrid, showDcmtTypesSelection, showExportForm, updateBatchUpdateForm, closeDcmtFormHandler, handleSignApprove, dcmtOperations: { downloadDcmtsAsync, runOperationAsync, }, relatedDocumentsInfo: { isOpenDetails, isOpenMaster, checkRelatedDcmtsArchiveCapability, checkManyToManyCapability, }, toppyOperations: { showApprovePopup, showRejectPopup, showReAssignPopup, showMoreInfoPopup, updateShowApprovePopup, updateShowRejectPopup, updateShowReAssignPopup, updateShowMoreInfoPopup } } = features;
|
|
408
|
+
// ----- Azioni della colonna di riga (showActionsColumn) -----------------------------------------
|
|
409
|
+
// Le voci di operationItems agiscono sui documenti selezionati o, in mancanza, su quello a fuoco:
|
|
410
|
+
// non accettano una riga come argomento. Il click sull'icona quindi azzera la selezione e porta il
|
|
411
|
+
// fuoco sulla riga cliccata, poi attende. L'attesa non è sul fuoco ma su selectedDcmtInfos, che
|
|
412
|
+
// l'hook ricalcola in un effect (un render più tardi): lanciare l'operazione prima significherebbe
|
|
413
|
+
// eseguirla sulla riga precedente.
|
|
414
|
+
const pendingRowActionRef = useRef(undefined);
|
|
415
|
+
// La callback è letta da una ref: dipendere dal prop renderebbe nuova requestRowAction, e con essa
|
|
416
|
+
// la colonna delle azioni, a ogni render del padre (vedi actionsColumn in TMSearchResultGrid)
|
|
417
|
+
const onRowDuplicateRequestRef = useRef(onRowDuplicateRequest);
|
|
418
|
+
onRowDuplicateRequestRef.current = onRowDuplicateRequest;
|
|
419
|
+
const requestRowAction = useCallback((operationId, rowData) => {
|
|
420
|
+
if (!showActionsColumn)
|
|
421
|
+
return;
|
|
422
|
+
if (rowData?.TID === undefined || rowData?.DID === undefined) {
|
|
423
|
+
ShowAlert({ message: SDKUI_Localizator.InvalidDcmt, mode: "warning", duration: 3000 });
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
// Duplica ridefinita dal chiamante: agisce sulla riga cliccata, senza toccare fuoco e selezione
|
|
427
|
+
if (operationId === 'dup' && onRowDuplicateRequestRef.current) {
|
|
428
|
+
onRowDuplicateRequestRef.current(rowData);
|
|
429
|
+
return;
|
|
430
|
+
}
|
|
431
|
+
pendingRowActionRef.current = { operationId, TID: rowData.TID, DID: rowData.DID };
|
|
432
|
+
isFirstAutoFocusRef.current = false;
|
|
433
|
+
setSelectedItems([]);
|
|
434
|
+
setFocusedItem(rowData);
|
|
435
|
+
}, [showActionsColumn]);
|
|
436
|
+
// La richiesta viene scartata se il documento sparisce dai risultati (es. refresh dopo
|
|
437
|
+
// un'eliminazione): senza questo resterebbe appesa e partirebbe al prossimo cambio di fuoco.
|
|
438
|
+
useEffect(() => { pendingRowActionRef.current = undefined; }, [selectedSearchResult, lastUpdateSearchTime]);
|
|
439
|
+
useEffect(() => {
|
|
440
|
+
if (!showActionsColumn)
|
|
441
|
+
return;
|
|
442
|
+
const pending = pendingRowActionRef.current;
|
|
443
|
+
if (!pending)
|
|
444
|
+
return;
|
|
445
|
+
// L'hook non ha ancora recepito la riga richiesta: si riproverà al prossimo aggiornamento
|
|
446
|
+
if (selectedDcmtInfos.length !== 1)
|
|
447
|
+
return;
|
|
448
|
+
if (selectedDcmtInfos[0].TID !== pending.TID || selectedDcmtInfos[0].DID !== pending.DID)
|
|
449
|
+
return;
|
|
450
|
+
pendingRowActionRef.current = undefined;
|
|
451
|
+
const operation = findOperationItemById(operationItems, pending.operationId);
|
|
452
|
+
// Ora che il fuoco è sulla riga, `disabled` riflette i permessi per quel documento
|
|
453
|
+
if (!operation || operation.disabled || operation.visible === false)
|
|
454
|
+
return;
|
|
455
|
+
operation.onClick?.();
|
|
456
|
+
}, [showActionsColumn, selectedDcmtInfos, operationItems]);
|
|
381
457
|
const deviceType = useDeviceType();
|
|
382
458
|
const isMobile = deviceType === DeviceType.MOBILE;
|
|
459
|
+
const hasSingleDcmtType = currentSearchResults.length === 1;
|
|
460
|
+
// Su mobile si vede un pannello per volta; su desktop selettore e griglia sono affiancati
|
|
461
|
+
const isSteppedLayout = showSelector && isMobile;
|
|
462
|
+
// Un solo tipo documento su desktop: non c'è niente da scegliere, quindi il selettore sparisce
|
|
463
|
+
// (larghezza 0, nessun separatore) e lo spazio va tutto alla griglia. Il menu "Altro" permette
|
|
464
|
+
// di riaprirlo (vedi canToggleDcmtTypesSelection nell'hook).
|
|
465
|
+
const isSelectorCollapsed = showSelector && !isSteppedLayout && hasSingleDcmtType && !showDcmtTypesSelection;
|
|
466
|
+
// Senza selettore lo spazio va tutto alla griglia; altrimenti a step su mobile, affiancati su desktop
|
|
467
|
+
const splitterSizes = (!showSelector || isSelectorCollapsed) ? ['0%', '100%']
|
|
468
|
+
: isSteppedLayout ? (navStep === 'results' ? ['0', '100%'] : ['100%', '0'])
|
|
469
|
+
: ['30%', '70%'];
|
|
383
470
|
const selectedDocs = getSelectedDcmtsOrFocused(selectedItems, focusedItem);
|
|
384
471
|
// Disable the "Sign/Approve" button if:
|
|
385
472
|
// 1. No document or multiple documents are selected, OR
|
|
@@ -400,8 +487,14 @@ handleNavigateToWGs, handleNavigateToDossiers, fetchRemoteCertificates, graphome
|
|
|
400
487
|
setSelectedSearchResult(undefined);
|
|
401
488
|
return;
|
|
402
489
|
}
|
|
490
|
+
// Un solo tipo documento: selezionalo e vai ai risultati, a meno che l'utente sia tornato indietro
|
|
403
491
|
if (searchResults.length === 1) {
|
|
492
|
+
if (navStep === 'selector') {
|
|
493
|
+
setSelectedSearchResult(undefined);
|
|
494
|
+
return;
|
|
495
|
+
}
|
|
404
496
|
setSelectedSearchResult(searchResults[0]);
|
|
497
|
+
setNavStep('results');
|
|
405
498
|
return;
|
|
406
499
|
}
|
|
407
500
|
// Se il TID precedentemente selezionato esiste ancora nei nuovi risultati, mantienilo.
|
|
@@ -415,6 +508,11 @@ handleNavigateToWGs, handleNavigateToDossiers, fetchRemoteCertificates, graphome
|
|
|
415
508
|
return;
|
|
416
509
|
}
|
|
417
510
|
}
|
|
511
|
+
// L'utente è sul selettore
|
|
512
|
+
if (isMobile && navStep !== 'results') {
|
|
513
|
+
setSelectedSearchResult(undefined);
|
|
514
|
+
return;
|
|
515
|
+
}
|
|
418
516
|
// Altrimenti seleziona il primo risultato ordinato
|
|
419
517
|
setSelectedSearchResult(orderByName(searchResults)[0]);
|
|
420
518
|
}, [searchResults]);
|
|
@@ -471,7 +569,9 @@ handleNavigateToWGs, handleNavigateToDossiers, fetchRemoteCertificates, graphome
|
|
|
471
569
|
return;
|
|
472
570
|
if (focusedItem?.DID != inputDID)
|
|
473
571
|
return;
|
|
474
|
-
|
|
572
|
+
if (focusedItem?.TID === undefined)
|
|
573
|
+
return;
|
|
574
|
+
onDcmtFormOpenChange(true, LayoutModes.Update);
|
|
475
575
|
}, [inputDID, formAutoOpen, focusedItem]);
|
|
476
576
|
// Quando openS4TViewer è true, apri automaticamente il viewer S4T
|
|
477
577
|
useEffect(() => {
|
|
@@ -529,49 +629,77 @@ handleNavigateToWGs, handleNavigateToDossiers, fetchRemoteCertificates, graphome
|
|
|
529
629
|
}, [currentMetadataValues]);
|
|
530
630
|
const getTitleHeader = () => {
|
|
531
631
|
let counters = (showSelector && disableAccordionIfSingleCategory && searchResults.length > 1) ? getSearchResultCountersSingleCategory(searchResults) : "";
|
|
632
|
+
// Nome del tipo documento selezionato, accodato al titolo
|
|
633
|
+
const selectedDcmtTypeName = selectedSearchResult?.fromName ?? (searchResults?.length === 1 ? searchResults[0]?.fromName : undefined);
|
|
634
|
+
const withSelectedDcmtTypeName = (baseTitle) => selectedDcmtTypeName ? `${baseTitle} - ${selectedDcmtTypeName}` : baseTitle;
|
|
532
635
|
if (title)
|
|
533
|
-
return title + counters;
|
|
534
|
-
let titleHeader = 'Ricerca per metadati';
|
|
636
|
+
return withSelectedDcmtTypeName(title) + counters;
|
|
637
|
+
let titleHeader = withSelectedDcmtTypeName('Ricerca per metadati');
|
|
535
638
|
switch (context) {
|
|
536
639
|
case SearchResultContext.MASTER_DETAIL:
|
|
537
640
|
case SearchResultContext.METADATA_SEARCH:
|
|
538
641
|
titleHeader = `${searchResults?.length > 1 ? selectedSearchResult?.fromName ?? 'Ricerca per metadati' : searchResults[0]?.fromName ?? 'Ricerca per metadati'}`;
|
|
539
642
|
break;
|
|
540
643
|
case SearchResultContext.FAVORITES_AND_RECENTS:
|
|
541
|
-
titleHeader = SDKUI_Localizator.FavoritesAndRecentDcmts;
|
|
644
|
+
titleHeader = withSelectedDcmtTypeName(SDKUI_Localizator.FavoritesAndRecentDcmts);
|
|
542
645
|
break;
|
|
543
646
|
case SearchResultContext.WORKFLOW_APPROVE:
|
|
544
|
-
titleHeader = SDKUI_Localizator.WorkflowApproval;
|
|
647
|
+
titleHeader = withSelectedDcmtTypeName(SDKUI_Localizator.WorkflowApproval);
|
|
545
648
|
break;
|
|
546
649
|
case SearchResultContext.FREE_SEARCH:
|
|
547
|
-
titleHeader =
|
|
650
|
+
titleHeader = withSelectedDcmtTypeName('Risultato della ricerca full text');
|
|
548
651
|
break;
|
|
549
652
|
}
|
|
550
653
|
return titleHeader + counters;
|
|
551
654
|
};
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
setSelectedSearchResult(undefined);
|
|
570
|
-
}
|
|
571
|
-
setSplitterSize(['100%', '0']);
|
|
572
|
-
onClose?.();
|
|
655
|
+
// Dai risultati si risale al selettore dei tipi documento
|
|
656
|
+
const canGoBackToSelector = isSteppedLayout && navStep === 'results' && selectedSearchResult !== undefined;
|
|
657
|
+
/**
|
|
658
|
+
* Back di tutti i pannelli (e X di chiusura se isClosable). Su mobile risale un livello alla volta:
|
|
659
|
+
* pannello secondario -> lista dei risultati -> selettore dei tipi documento -> uscita.
|
|
660
|
+
* Su desktop i pannelli sono affiancati, quindi resta solo l'uscita.
|
|
661
|
+
*
|
|
662
|
+
* @param fromSecondaryPanel - true se il back arriva da un pannello secondario
|
|
663
|
+
*/
|
|
664
|
+
const onBack = useCallback((fromSecondaryPanel = false) => {
|
|
665
|
+
// Non è previsto nessun modo di uscire: non fare niente
|
|
666
|
+
if (!showBackButton && !isClosable)
|
|
667
|
+
return;
|
|
668
|
+
// Torna alla lista senza toccare gli stati: l'utente deve ritrovare la sua selezione
|
|
669
|
+
if (fromSecondaryPanel) {
|
|
670
|
+
showMainPanelRef.current?.();
|
|
671
|
+
return;
|
|
573
672
|
}
|
|
574
|
-
|
|
673
|
+
// Sia il ritorno al selettore sia l'uscita ripartono da una lista pulita
|
|
674
|
+
setSelectedSearchResult(undefined);
|
|
675
|
+
setFocusedItem(undefined);
|
|
676
|
+
setSelectedItems([]);
|
|
677
|
+
setSelectedRowKeysFromDataGrid([]);
|
|
678
|
+
setCurrentDcmt(undefined);
|
|
679
|
+
setCurrentMetadataValues([]);
|
|
680
|
+
setShowIndexingInfo(false);
|
|
681
|
+
isFirstAutoFocusRef.current = true;
|
|
682
|
+
// Il chiamante può tenere allineato il suo TID selezionato (es. selectedSearchResultTID)
|
|
683
|
+
onSelectedTIDCleared?.();
|
|
684
|
+
// [2] l'utente ha chiesto la lista: resta lì finché non sceglie lui, niente auto-selezione.
|
|
685
|
+
// [1] si esce: si riparte da capo, quindi l'auto-selezione torna permessa.
|
|
686
|
+
setNavStep(canGoBackToSelector ? 'selector' : 'auto');
|
|
687
|
+
// [2] C'è ancora un livello sopra: restiamo dentro, sul selettore
|
|
688
|
+
if (canGoBackToSelector)
|
|
689
|
+
return;
|
|
690
|
+
// [1] Si esce e si avvisa il chiamante
|
|
691
|
+
onClose?.();
|
|
692
|
+
}, [canGoBackToSelector, showBackButton, isClosable, onClose, onSelectedTIDCleared]);
|
|
693
|
+
/**
|
|
694
|
+
* Back del pannello lista. `undefined` = freccia non renderizzata, quindi la mostriamo solo se
|
|
695
|
+
* ha dove tornare: uno step intermedio, o un onClose per uscire. Con `isClosable` basta la X.
|
|
696
|
+
*/
|
|
697
|
+
const backHandler = (showBackButton && !isClosable && (canGoBackToSelector || onClose !== undefined)) ? onBack : undefined;
|
|
698
|
+
/**
|
|
699
|
+
* Back dei pannelli secondari: la stessa onBack marcata come livello [3]. Solo su mobile:
|
|
700
|
+
* su desktop stanno affiancati alla lista e non c'è niente da cui tornare.
|
|
701
|
+
*/
|
|
702
|
+
const backHandlerSecondary = useMemo(() => (isMobile && backHandler) ? () => backHandler(true) : undefined, [isMobile, backHandler]);
|
|
575
703
|
const refreshDataGridAfterRemoveAsync = async () => {
|
|
576
704
|
let index = selectedSearchResult?.dtdResult?.columns?.findIndex(col => col.caption === 'DID');
|
|
577
705
|
let selectedRows = [];
|
|
@@ -603,21 +731,6 @@ handleNavigateToWGs, handleNavigateToDossiers, fetchRemoteCertificates, graphome
|
|
|
603
731
|
return newResults;
|
|
604
732
|
});
|
|
605
733
|
};
|
|
606
|
-
/**
|
|
607
|
-
* Restituisce l'handler onBack per i pannelli, evitando duplicazione di codice.
|
|
608
|
-
* @param isMainPanel - Se true, è il pannello principale dei risultati di ricerca
|
|
609
|
-
*/
|
|
610
|
-
const getOnBackHandler = (isMainPanel = false) => {
|
|
611
|
-
// Se showBackButton è false, non mostrare mai il back
|
|
612
|
-
if (showBackButton === false)
|
|
613
|
-
return undefined;
|
|
614
|
-
// Mobile: mostra back su tutti i pannelli (se showBackButton è definito e non è closable)
|
|
615
|
-
if (isMobile) {
|
|
616
|
-
return (showBackButton !== undefined && !isClosable) ? onBack : undefined;
|
|
617
|
-
}
|
|
618
|
-
// Desktop: mostra back solo sul pannello principale dei risultati (se showBackButton è definito e non è closable)
|
|
619
|
-
return (showBackButton !== undefined && isMainPanel && !isClosable) ? onBack : undefined;
|
|
620
|
-
};
|
|
621
734
|
const removeDcmtFromFavsOrRecents = async () => {
|
|
622
735
|
switch (selectedSearchResult?.category) {
|
|
623
736
|
case "Favorites":
|
|
@@ -634,9 +747,9 @@ handleNavigateToWGs, handleNavigateToDossiers, fetchRemoteCertificates, graphome
|
|
|
634
747
|
};
|
|
635
748
|
const onSearchResultSelectionChanged = (e) => {
|
|
636
749
|
setSelectedSearchResult(e);
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
750
|
+
// Scelto il tipo documento si passa ai risultati (a livello di layout è ignorato se i due
|
|
751
|
+
// step sono affiancati, ma vale comunque come "l'utente non è più fermo sul selettore")
|
|
752
|
+
setNavStep('results');
|
|
640
753
|
onSelectedTIDChanged?.(e.fromTID);
|
|
641
754
|
};
|
|
642
755
|
const showToppyForApprove = useMemo(() => {
|
|
@@ -660,14 +773,15 @@ handleNavigateToWGs, handleNavigateToDossiers, fetchRemoteCertificates, graphome
|
|
|
660
773
|
&& !showTodoDcmtForm);
|
|
661
774
|
}, [showToppyForApprove, showToppyDraggableHelpCenter, selectedDocs, showApprovePopup, showRejectPopup, showReAssignPopup, showMoreInfoPopup, editPdfForm, openS4TViewer, showTodoDcmtForm]);
|
|
662
775
|
const searchResutlToolbar = _jsxs(_Fragment, { children: [context === SearchResultContext.FAVORITES_AND_RECENTS &&
|
|
663
|
-
_jsx("div", { style: { display: 'flex', alignItems: 'center', gap: '5px' }, children: _jsx(TMButton, { btnStyle: 'icon', icon: _jsx(IconDelete, { color: 'white' }), caption: "Rimuovi da " + (selectedSearchResult?.category === "Favorites" ? '"Preferiti"' : '"Recenti"'), disabled: getSelectedDcmtsOrFocused(selectedItems, focusedItem).length <= 0, onClick: removeDcmtFromFavsOrRecents }) }), _jsx(TMButton, { btnStyle: 'icon', icon: _jsx(IconRefresh, { color: 'white' }), caption: SDKUI_Localizator.Refresh, onClick:
|
|
776
|
+
_jsx("div", { style: { display: 'flex', alignItems: 'center', gap: '5px' }, children: _jsx(TMButton, { btnStyle: 'icon', icon: _jsx(IconDelete, { color: 'white' }), caption: "Rimuovi da " + (selectedSearchResult?.category === "Favorites" ? '"Preferiti"' : '"Recenti"'), disabled: getSelectedDcmtsOrFocused(selectedItems, focusedItem).length <= 0, onClick: removeDcmtFromFavsOrRecents }) }), _jsx(TMButton, { btnStyle: 'icon', icon: _jsx(IconRefresh, { color: 'white' }), caption: SDKUI_Localizator.Refresh, onClick: handleRefreshClick }), _jsx(TMContextMenu, { items: operationItems, trigger: "left", children: _jsx(IconMenuVertical, { color: 'white', cursor: 'pointer' }) }), showToolbarCloseButton && onClose &&
|
|
777
|
+
_jsx(TMButton, { btnStyle: 'icon', icon: _jsx(IconCloseOutline, { color: 'white' }), caption: SDKUI_Localizator.Close, onClick: onClose })] });
|
|
664
778
|
const tmSearchResult = useMemo(() => (!searchResults || searchResults.length <= 0)
|
|
665
779
|
? _jsxs("div", { style: { display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', height: '100%', width: '100%' }, children: [_jsx(IconBoard, { fontSize: 96 }), showNoDcmtFoundMessage && _jsx("div", { style: { fontSize: "15px", marginTop: "10px" }, children: SDKUI_Localizator.NoDcmtFound }), openAddDocumentForm && _jsx("div", { style: { marginTop: "10px" }, children: _jsx(TMButton, { fontSize: "15px", icon: _jsx("i", { className: 'dx-icon-share' }), caption: SDKUI_Localizator.Share, onClick: openAddDocumentForm }) })] })
|
|
666
780
|
:
|
|
667
|
-
_jsxs(_Fragment, { children: [_jsxs(TMLayoutItem, { height: '100%', children: [_jsxs("div", { ref: floatingBarContainerRef, style: { position: 'relative', height: '100%', width: '100%' }, children: [_jsxs(TMSplitterLayout, { direction: 'horizontal', overflow: 'visible', separatorSize: Gutters.getGutters(), separatorActiveColor: 'transparent', separatorColor: 'transparent', min: ['0', '0'], showSeparator: showSelector &&
|
|
668
|
-
_jsx(TMLayoutItem, { children: _jsx(TMSearchResultSelector, { searchResults: currentSearchResults, disableAccordionIfSingleCategory: disableAccordionIfSingleCategory, selectedTID: selectedSearchResultTID, selectedSearchResult: selectedSearchResult, autoSelectFirst: !isMobile ||
|
|
781
|
+
_jsxs(_Fragment, { children: [_jsxs(TMLayoutItem, { height: '100%', children: [_jsxs("div", { ref: floatingBarContainerRef, style: { position: 'relative', height: '100%', width: '100%' }, children: [_jsxs(TMSplitterLayout, { direction: 'horizontal', overflow: isSteppedLayout ? 'hidden' : 'visible', separatorSize: Gutters.getGutters(), separatorActiveColor: 'transparent', separatorColor: 'transparent', min: ['0', '0'], showSeparator: showSelector && !isSteppedLayout && !isSelectorCollapsed, start: splitterSizes, children: [showSelector ?
|
|
782
|
+
_jsx(TMLayoutItem, { children: _jsx(TMSearchResultSelector, { searchResults: currentSearchResults, disableAccordionIfSingleCategory: disableAccordionIfSingleCategory, selectedTID: selectedSearchResultTID, selectedSearchResult: selectedSearchResult, autoSelectFirst: !isMobile || hasSingleDcmtType, onSelectionChanged: onSearchResultSelectionChanged }) })
|
|
669
783
|
:
|
|
670
|
-
_jsx(_Fragment, {}), _jsx(TMLayoutItem, { children: _jsx(TMSearchResultGrid, { openInOffice: openInOffice, fromDTD: fromDTD, operationItems: operationItems, allUsers: allUsers, inputFocusedItem: focusedItem, inputSelectedItems: selectedItems, showExportForm: showExportForm, onFocusedItemChanged: handleFocusedItemChangedFromGrid, onDownloadDcmtsAsync: async (inputDcmts, downloadType, downloadMode, _y, confirmAttachments) => await downloadDcmtsAsync({ inputDcmts, downloadType, downloadMode, onFileDownloaded: onFileOpened, confirmAttachments }), lastUpdateSearchTime: lastUpdateSearchTime, searchResult: searchResults.length > 1 ? selectedSearchResult : searchResults[0], onSelectionChanged: (items) => { setSelectedItems(items); }, onDblClick: () => openFormHandler(LayoutModes.Update), showSearchTMDatagrid: showSearchTMDatagrid, onVisibleItemChanged: setVisibleItems, updateDataColumnsFromDataGrid: updateDataColumnsFromDataGrid, updateDataSourceFromDataGrid: updateDataSourceFromDataGrid, updateSelectedRowKeysFromDataGrid: updateSelectedRowKeysFromDataGrid, disableAutoFocus: autoFocusFirstRow === false && isFirstAutoFocusRef.current, dcmtsReturned: dcmtsReturned, dcmtsFound: dcmtsFound }) })] }), renderFloatingBar] }), _jsx(TMToppyDraggableHelpCenter, { usePortal: toppyHelpCenterUsePortal, isVisible: isToppyHelpCenterVisible, content: _jsx("div", { style: { display: 'flex', flexDirection: 'column', gap: '10px' }, children: _jsx(WorkFlowOperationButtons, { dtd: fromDTD, deviceType: deviceType, onApprove: () => {
|
|
784
|
+
_jsx(_Fragment, {}), _jsx(TMLayoutItem, { children: _jsx(TMSearchResultGrid, { openInOffice: openInOffice, fromDTD: fromDTD, operationItems: operationItems, allUsers: allUsers, inputFocusedItem: focusedItem, inputSelectedItems: selectedItems, showExportForm: showExportForm, onFocusedItemChanged: handleFocusedItemChangedFromGrid, onDownloadDcmtsAsync: async (inputDcmts, downloadType, downloadMode, _y, confirmAttachments) => await downloadDcmtsAsync({ inputDcmts, downloadType, downloadMode, onFileDownloaded: onFileOpened, confirmAttachments }), lastUpdateSearchTime: lastUpdateSearchTime, searchResult: searchResults.length > 1 ? selectedSearchResult : searchResults[0], onSelectionChanged: (items) => { setSelectedItems(items); }, onDblClick: () => openFormHandler(LayoutModes.Update), showSearchTMDatagrid: showSearchTMDatagrid, onVisibleItemChanged: setVisibleItems, updateDataColumnsFromDataGrid: updateDataColumnsFromDataGrid, updateDataSourceFromDataGrid: updateDataSourceFromDataGrid, updateSelectedRowKeysFromDataGrid: updateSelectedRowKeysFromDataGrid, disableAutoFocus: autoFocusFirstRow === false && isFirstAutoFocusRef.current, dcmtsReturned: dcmtsReturned, dcmtsFound: dcmtsFound, showCounterConfig: showCounterConfig, counterConfig: counterConfig, showActionsColumn: showActionsColumn, compactPager: compactPager, onRowActionRequest: requestRowAction }) })] }), renderFloatingBar] }), _jsx(TMToppyDraggableHelpCenter, { usePortal: toppyHelpCenterUsePortal, isVisible: isToppyHelpCenterVisible, content: _jsx("div", { style: { display: 'flex', flexDirection: 'column', gap: '10px' }, children: _jsx(WorkFlowOperationButtons, { dtd: fromDTD, deviceType: deviceType, onApprove: () => {
|
|
671
785
|
updateShowApprovePopup(true);
|
|
672
786
|
}, onSignApprove: () => {
|
|
673
787
|
handleSignApprove();
|
|
@@ -687,7 +801,6 @@ handleNavigateToWGs, handleNavigateToDossiers, fetchRemoteCertificates, graphome
|
|
|
687
801
|
showApprovePopup,
|
|
688
802
|
showRejectPopup,
|
|
689
803
|
showReAssignPopup,
|
|
690
|
-
isOpenBatchUpdate,
|
|
691
804
|
isOpenDetails,
|
|
692
805
|
isOpenMaster,
|
|
693
806
|
isOpenDcmtForm,
|
|
@@ -698,6 +811,10 @@ handleNavigateToWGs, handleNavigateToDossiers, fetchRemoteCertificates, graphome
|
|
|
698
811
|
openS4TViewer,
|
|
699
812
|
showBackButton,
|
|
700
813
|
isMobile,
|
|
814
|
+
navStep,
|
|
815
|
+
isSteppedLayout,
|
|
816
|
+
isSelectorCollapsed,
|
|
817
|
+
currentSearchResults,
|
|
701
818
|
currentMetadataValues,
|
|
702
819
|
onRefreshSearchAsyncDatagrid,
|
|
703
820
|
handleNavigateToWGs,
|
|
@@ -705,9 +822,14 @@ handleNavigateToWGs, handleNavigateToDossiers, fetchRemoteCertificates, graphome
|
|
|
705
822
|
editPdfForm,
|
|
706
823
|
showNoDcmtFoundMessage
|
|
707
824
|
]);
|
|
708
|
-
|
|
825
|
+
/**
|
|
826
|
+
* Il risultato è davvero a video: le pagine restano montate anche in secondo piano, e senza questo
|
|
827
|
+
* bacheca e anteprima scaricherebbero il documento fuori campo.
|
|
828
|
+
*/
|
|
829
|
+
const isSearchResultOnScreen = isVisible && !isOpenDcmtForm && !isOpenDetails && !isOpenMaster;
|
|
830
|
+
const tmBlog = useMemo(() => _jsx(TMDcmtBlog, { tid: focusedItem?.TID, did: focusedItem?.DID, isPageVisible: isSearchResultOnScreen, fetchBlogDataTrigger: refreshBlogTrigger, allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback, editTaskCallback: editTaskCallback, handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers }), [focusedItem, allTasks, refreshBlogTrigger, isSearchResultOnScreen, handleNavigateToWGs, handleNavigateToDossiers, onRefreshBlogDatagrid]);
|
|
709
831
|
const tmSysMetadata = useMemo(() => _jsx(TMMetadataValues, { layoutMode: LayoutModes.Update, openChooserBySingleClick: true, TID: focusedItem?.TID, isReadOnly: true, deviceType: deviceType, metadataValues: currentMetadataValues.filter(o => (o.mid != undefined && o.mid <= 100)), metadataValuesOrig: currentMetadataValues.filter(o => (o.mid != undefined && o.mid <= 100)), validationItems: [] }), [focusedItem, currentMetadataValues, deviceType]);
|
|
710
|
-
const tmDcmtPreview = useMemo(() => _jsx(TMDcmtPreviewWrapper, { refreshPreviewTrigger: refreshPreviewTrigger, currentDcmt: currentDcmt, onBack:
|
|
832
|
+
const tmDcmtPreview = useMemo(() => _jsx(TMDcmtPreviewWrapper, { refreshPreviewTrigger: refreshPreviewTrigger, currentDcmt: currentDcmt, isPageVisible: isSearchResultOnScreen, onBack: backHandlerSecondary }), [currentDcmt, refreshPreviewTrigger, isSearchResultOnScreen, backHandlerSecondary]);
|
|
711
833
|
// Auto-fetch indexing info when drawer is open and focusedItem changes
|
|
712
834
|
useEffect(() => {
|
|
713
835
|
if (!focusedItem || !showIndexingInfo)
|
|
@@ -762,8 +884,24 @@ handleNavigateToWGs, handleNavigateToDossiers, fetchRemoteCertificates, graphome
|
|
|
762
884
|
if (!ftExplanation) {
|
|
763
885
|
return (_jsxs(StyledPlaceholder, { children: [" ", _jsx("p", { children: "Nessuna info disponibile per questo documento" }), " "] }));
|
|
764
886
|
}
|
|
765
|
-
return (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', height: '100%', overflow: 'hidden', width: '100%' }, children: [_jsx("div", { style: { padding: '10px', overflow: 'auto', flex: 1 }, children: _jsx("div", { dangerouslySetInnerHTML: { __html: ftExplanation } }) }), _jsxs(StyledIndexingInfoSection, { children: [_jsxs(StyledIndexingToggle, { onClick: handleToggleIndexingInfo, disabled: loadingIndexingInfo, children: [_jsx(StyledLeftContent, { children: _jsx("span", { children: SDKUI_Localizator.IndexingInformation }) }), _jsx(StyledRightContent, { children: _jsx(StyledChevron, {
|
|
887
|
+
return (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', height: '100%', overflow: 'hidden', width: '100%' }, children: [_jsx("div", { style: { padding: '10px', overflow: 'auto', flex: 1 }, children: _jsx("div", { dangerouslySetInnerHTML: { __html: ftExplanation } }) }), _jsxs(StyledIndexingInfoSection, { children: [_jsxs(StyledIndexingToggle, { onClick: handleToggleIndexingInfo, disabled: loadingIndexingInfo, children: [_jsx(StyledLeftContent, { children: _jsx("span", { children: SDKUI_Localizator.IndexingInformation }) }), _jsx(StyledRightContent, { children: _jsx(StyledChevron, { $isOpen: showIndexingInfo, children: "\u25BC" }) })] }), showIndexingInfo && indexingInfo && (_jsxs(StyledIndexingInfoBox, { children: [_jsx("div", { dangerouslySetInnerHTML: { __html: indexingInfo } }), loadingIndexingInfo && (_jsxs("div", { style: { position: 'absolute', top: '50%', left: '50%', transform: 'translate(-50%, -50%)', background: 'rgba(255, 255, 255, 0.9)', padding: '10px', borderRadius: '4px', boxShadow: '0 2px 8px rgba(0,0,0,0.15)' }, children: [SDKUI_Localizator.Loading, "..."] }))] }))] })] }));
|
|
766
888
|
}, [selectedSearchResult, focusedItem, indexingInfo, showIndexingInfo, loadingIndexingInfo]);
|
|
889
|
+
/**
|
|
890
|
+
* Su mobile i pannelli si mostrano uno per volta, quindi il layout non va ricordato; con groupId
|
|
891
|
+
* i pannelli sono di un panel manager esterno, che ha un layout suo. Senza la barra laterale
|
|
892
|
+
* l'utente non può aprire/chiudere i pannelli: non ha senso applicargli il layout salvato (li
|
|
893
|
+
* troverebbe aperti senza poterli chiudere) né lasciargli sporcare quello condiviso.
|
|
894
|
+
* Il layout salvato vale solo per il login con Surfer: gli altri moduli hanno layout propri.
|
|
895
|
+
*/
|
|
896
|
+
const isLayoutPersisted = SDK_Globals.tmSession?.SessionDescr?.appModuleID === AppModules.SURFER && !isMobile && !groupId?.length && showSearchResultSidebar && PERSISTED_LAYOUT_CONTEXTS.includes(context);
|
|
897
|
+
/**
|
|
898
|
+
* Pannelli che questo risultato non può mostrare (la bacheca è l'unico, vedi PanelDisabledStateHandler).
|
|
899
|
+
* Il layout è condiviso con gli altri risultati aperti: qui non vanno aperti quando il layout lo chiede,
|
|
900
|
+
* e il loro stato salvato non va toccato, altrimenti li si chiuderebbe dove invece sono attivi.
|
|
901
|
+
*/
|
|
902
|
+
const disabledLayoutPanelIds = isBoardDisabled ? ['tmBlog'] : [];
|
|
903
|
+
/** Bacheca aperta nel layout salvato: da riaprire quando il tipo documento torna a prevederla */
|
|
904
|
+
const savedBlogVisible = isLayoutPersisted && (getSearchResultPanelLayout()['tmBlog']?.visible ?? false);
|
|
767
905
|
const allInitialPanelVisibility = {
|
|
768
906
|
'tmSearchResult': true,
|
|
769
907
|
'tmBlog': false,
|
|
@@ -786,9 +924,11 @@ handleNavigateToWGs, handleNavigateToDossiers, fetchRemoteCertificates, graphome
|
|
|
786
924
|
component: tmSearchResult,
|
|
787
925
|
panelContainer: {
|
|
788
926
|
title: getTitleHeader(),
|
|
927
|
+
enableTitleMarquee: true,
|
|
789
928
|
showHeader: showToolbarHeader,
|
|
790
929
|
allowMaximize: !isMobile,
|
|
791
|
-
onBack:
|
|
930
|
+
onBack: backHandler,
|
|
931
|
+
backCaption: backCaption,
|
|
792
932
|
onClose: isClosable ? onBack : undefined,
|
|
793
933
|
toolbar: searchResutlToolbar
|
|
794
934
|
},
|
|
@@ -803,7 +943,7 @@ handleNavigateToWGs, handleNavigateToDossiers, fetchRemoteCertificates, graphome
|
|
|
803
943
|
panelContainer: {
|
|
804
944
|
title: SDKUI_Localizator.BlogCase,
|
|
805
945
|
allowMaximize: !isMobile,
|
|
806
|
-
onBack:
|
|
946
|
+
onBack: backHandlerSecondary,
|
|
807
947
|
}
|
|
808
948
|
},
|
|
809
949
|
toolbarOptions: { icon: _jsx(IconBoard, { fontSize: 24 }), visible: getSearchToolbarVisibility(SDK_Globals.tmSession?.SessionDescr?.appModuleID ?? AppModules.SURFER).tmBlog, orderNumber: 2, isActive: allInitialPanelVisibility['tmBlog'] }
|
|
@@ -816,7 +956,7 @@ handleNavigateToWGs, handleNavigateToDossiers, fetchRemoteCertificates, graphome
|
|
|
816
956
|
panelContainer: {
|
|
817
957
|
title: SDKUI_Localizator.MetadataSystem,
|
|
818
958
|
allowMaximize: !isMobile,
|
|
819
|
-
onBack:
|
|
959
|
+
onBack: backHandlerSecondary,
|
|
820
960
|
}
|
|
821
961
|
},
|
|
822
962
|
toolbarOptions: { icon: _jsx(IconDcmtTypeSys, { fontSize: 24 }), visible: getSearchToolbarVisibility(SDK_Globals.tmSession?.SessionDescr?.appModuleID ?? AppModules.SURFER).tmSysMetadata, orderNumber: 3, isActive: allInitialPanelVisibility['tmSysMetadata'] }
|
|
@@ -830,7 +970,7 @@ handleNavigateToWGs, handleNavigateToDossiers, fetchRemoteCertificates, graphome
|
|
|
830
970
|
panelContainer: {
|
|
831
971
|
title: SDKUI_Localizator.ResultDetails,
|
|
832
972
|
allowMaximize: !isMobile,
|
|
833
|
-
onBack:
|
|
973
|
+
onBack: backHandlerSecondary,
|
|
834
974
|
}
|
|
835
975
|
},
|
|
836
976
|
toolbarOptions: { icon: _jsx(IconPlatform, { fontSize: 20 }), visible: getSearchToolbarVisibility(SDK_Globals.tmSession?.SessionDescr?.appModuleID ?? AppModules.SURFER).tmFullTextSearch, orderNumber: 4, isActive: allInitialPanelVisibility['tmFullTextSearch'] }
|
|
@@ -844,21 +984,49 @@ handleNavigateToWGs, handleNavigateToDossiers, fetchRemoteCertificates, graphome
|
|
|
844
984
|
},
|
|
845
985
|
toolbarOptions: { icon: _jsx(IconShow, { fontSize: 24 }), visible: getSearchToolbarVisibility(SDK_Globals.tmSession?.SessionDescr?.appModuleID ?? AppModules.SURFER).tmDcmtPreview, orderNumber: context === SearchResultContext.FREE_SEARCH ? 5 : 4, isActive: allInitialPanelVisibility['tmDcmtPreview'] }
|
|
846
986
|
}
|
|
847
|
-
], [tmSearchResult, tmBlog, tmSysMetadata, tmDcmtPreview, tmFullTextSearch, showToolbarHeader, context, isMobile]);
|
|
848
|
-
|
|
987
|
+
], [tmSearchResult, tmBlog, tmSysMetadata, tmDcmtPreview, tmFullTextSearch, showToolbarHeader, context, isMobile, backHandler, backHandlerSecondary, isClosable, onBack, backCaption]);
|
|
988
|
+
/** Contenuto del panel manager: con groupId sta nel provider del contenitore, altrimenti in quello qui sotto */
|
|
989
|
+
const panelManagerContent = (_jsxs(_Fragment, { children: [_jsx(PanelDisabledStateHandler, { isBoardDisabled: isBoardDisabled, savedBlogVisible: savedBlogVisible }), isLayoutPersisted && _jsx(SavedLayoutSyncHandler, { disabledPanelIds: disabledLayoutPanelIds }), _jsx(ShowMainPanelBridge, { showMainPanelRef: showMainPanelRef }), _jsx(TMPanelManagerContainer, { panels: initialPanels, direction: "horizontal", parentId: groupId, showToolbar: showSearchResultSidebar })] }));
|
|
990
|
+
return (_jsxs(StyledMultiViewPanel, { $isVisible: isVisible, children: [_jsx(StyledMultiViewPanel, { $isVisible: (!isOpenDcmtForm || isDcmtFormModal) && !isOpenDetails && !isOpenMaster, style: {
|
|
849
991
|
display: 'flex',
|
|
850
992
|
flexDirection: isMobile ? 'column' : 'row',
|
|
851
993
|
justifyContent: 'space-between',
|
|
852
994
|
gap: Gutters.getGutters(),
|
|
853
995
|
width: '100%',
|
|
854
996
|
height: '100%',
|
|
855
|
-
}, children: _jsx(
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
997
|
+
}, children: _jsx(TMLayoutContainer, { direction: 'vertical', children: (groupId && groupId.length > 0) ? panelManagerContent
|
|
998
|
+
// Senza le prop di persistenza il provider si comporta come quello base:
|
|
999
|
+
// i contesti che non ricordano il layout restano come prima
|
|
1000
|
+
: _jsx(TMPanelManagerWithPersistenceProvider, { panels: initialPanels, initialVisibility: allInitialPanelVisibility, defaultDimensions: initialPanelDimensions, initialDimensions: initialPanelDimensions, initialMobilePanelId: 'tmSearchResult', isPersistenceEnabled: isLayoutPersisted && hasSearchResultPanelLayout(), persistPanelStates: isLayoutPersisted ? (state) => saveSearchResultPanelLayout(state, disabledLayoutPanelIds) : undefined, persistedPanelStates: isLayoutPersisted ? getSearchResultPanelLayout() : undefined, children: panelManagerContent }) }) }), renderDcmtOperations] }));
|
|
859
1001
|
};
|
|
860
1002
|
export default TMSearchResult;
|
|
861
|
-
|
|
1003
|
+
/** Cerca una voce di operazione per id, anche dentro i sottomenu */
|
|
1004
|
+
const findOperationItemById = (items, id) => {
|
|
1005
|
+
for (const item of items) {
|
|
1006
|
+
if (item.id === id)
|
|
1007
|
+
return item;
|
|
1008
|
+
const found = item.submenu ? findOperationItemById(item.submenu, id) : undefined;
|
|
1009
|
+
if (found)
|
|
1010
|
+
return found;
|
|
1011
|
+
}
|
|
1012
|
+
return undefined;
|
|
1013
|
+
};
|
|
1014
|
+
/**
|
|
1015
|
+
* Azioni della colonna di riga. Gli id sono quelli di useDocumentOperations, così il comportamento è
|
|
1016
|
+
* lo stesso del menu contestuale; icone e colori sono allineati alle altre griglie mentre il tooltip
|
|
1017
|
+
* resta il nome dell'operazione. "Cancella" è la cancellazione logica: ripristino ed eliminazione
|
|
1018
|
+
* fisica restano nel menu contestuale, dove la scelta è esplicita.
|
|
1019
|
+
*/
|
|
1020
|
+
const rowActions = [
|
|
1021
|
+
{ operationId: 'open-form', icon: _jsx(IconEdit, { fontSize: 18, color: TMColors.primary }) },
|
|
1022
|
+
{ operationId: 'dup', icon: _jsx(IconDuplicate, { fontSize: 18, color: TMColors.tertiary }) },
|
|
1023
|
+
{ operationId: 'del-log', icon: _jsx(IconDelete, { fontSize: 18, color: TMColors.error }), isVisible: (rowData) => rowData?.ISLOGDEL != 1 },
|
|
1024
|
+
];
|
|
1025
|
+
const rowActionsStyles = {
|
|
1026
|
+
cell: { display: 'flex', alignItems: 'center', justifyContent: 'center', gap: '14px' },
|
|
1027
|
+
icon: { cursor: 'pointer', display: 'flex' },
|
|
1028
|
+
};
|
|
1029
|
+
const TMSearchResultGrid = ({ openInOffice, fromDTD, operationItems, allUsers, inputFocusedItem, allowMultipleSelection = true, showExportForm = false, onFocusedItemChanged, onDownloadDcmtsAsync, onVisibleItemChanged, inputSelectedItems = [], lastUpdateSearchTime, searchResult, onSelectionChanged, onDblClick, showSearchTMDatagrid, updateDataColumnsFromDataGrid, updateDataSourceFromDataGrid, updateSelectedRowKeysFromDataGrid, disableAutoFocus = false, dcmtsReturned, dcmtsFound, showCounterConfig = true, counterConfig, showActionsColumn = false, compactPager = false, onRowActionRequest, }) => {
|
|
862
1030
|
const [dataSource, setDataSource] = useState();
|
|
863
1031
|
const [columns, setColumns] = useState([]);
|
|
864
1032
|
const [selectedRowKeys, setSelectedRowKeys] = useState([]);
|
|
@@ -879,8 +1047,8 @@ const TMSearchResultGrid = ({ openInOffice, fromDTD, operationItems, allUsers, i
|
|
|
879
1047
|
useEffect(() => {
|
|
880
1048
|
updateDataSourceFromDataGrid(dataSource ?? []);
|
|
881
1049
|
}, [dataSource]);
|
|
882
|
-
const { loadDataListsAsync, renderDataListCell, dataListsCache } = useDataListItem();
|
|
883
|
-
const { loadUsersAsync, renderUserIdViewer, usersCache } = useDataUserIdItem();
|
|
1050
|
+
const { loadDataListsAsync, renderDataListCell, dataListsCache, getDataListItem } = useDataListItem();
|
|
1051
|
+
const { loadUsersAsync, renderUserIdViewer, usersCache, getUserItem, getCompleteUserName } = useDataUserIdItem();
|
|
884
1052
|
useEffect(() => {
|
|
885
1053
|
// Sincronizza focusedItem con inputFocusedItem dal padre
|
|
886
1054
|
if (deepCompare(inputFocusedItem, focusedItem))
|
|
@@ -1000,42 +1168,14 @@ const TMSearchResultGrid = ({ openInOffice, fromDTD, operationItems, allUsers, i
|
|
|
1000
1168
|
const getDisplayFormat = useCallback((col) => {
|
|
1001
1169
|
if (col.dataType === DataColumnTypes.Text)
|
|
1002
1170
|
return undefined;
|
|
1003
|
-
|
|
1004
|
-
const formatCulture = col
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
case MetadataFormats.ShortDateLongTime: return value.toLocaleString(formatCulture, formatCulture == "it-IT" ? { year: "numeric", month: "2-digit", day: "2-digit", hour: '2-digit', minute: '2-digit', second: '2-digit' } : { dateStyle: 'short', timeStyle: 'medium' }).replace(',', '');
|
|
1012
|
-
case MetadataFormats.ShortDateShortTime: return value.toLocaleString(formatCulture, formatCulture == "it-IT" ? { year: "numeric", month: "2-digit", day: "2-digit", hour: '2-digit', minute: '2-digit' } : { dateStyle: 'short', timeStyle: 'short' }).replace(',', '');
|
|
1013
|
-
case MetadataFormats.LongDate: return value.toLocaleString(formatCulture, { weekday: "long", year: "numeric", month: "long", day: "numeric" });
|
|
1014
|
-
case MetadataFormats.LongTime: return value.toLocaleString(formatCulture, { timeStyle: 'medium' });
|
|
1015
|
-
case MetadataFormats.LongDateLongTime: return value.toLocaleString(formatCulture, { weekday: "long", year: "numeric", month: "long", day: "numeric", hour: '2-digit', minute: '2-digit', second: '2-digit' });
|
|
1016
|
-
case MetadataFormats.LongDateShortTime: return value.toLocaleString(formatCulture, { weekday: "long", year: "numeric", month: "long", day: "numeric", hour: '2-digit', minute: '2-digit' });
|
|
1017
|
-
default: return value.toLocaleString(formatCulture, formatCulture == "it-IT" ? { year: "numeric", month: "2-digit", day: "2-digit" } : { dateStyle: 'short' });
|
|
1018
|
-
}
|
|
1019
|
-
}
|
|
1020
|
-
};
|
|
1021
|
-
}
|
|
1022
|
-
if (col.dataType === DataColumnTypes.Number) {
|
|
1023
|
-
return {
|
|
1024
|
-
formatter: function (value) {
|
|
1025
|
-
return value.toLocaleString(formatCulture, { useGrouping: format == MetadataFormats.NumberWithThousandsSeparator });
|
|
1026
|
-
}
|
|
1027
|
-
};
|
|
1028
|
-
}
|
|
1029
|
-
if (format == MetadataFormats.None)
|
|
1030
|
-
return undefined;
|
|
1031
|
-
if (format == MetadataFormats.CurrencyEuro)
|
|
1032
|
-
return { type: 'currency', precision: 2, currency: "EUR" };
|
|
1033
|
-
if (format == MetadataFormats.CurrencyDollar)
|
|
1034
|
-
return { type: 'currency', precision: 2, currency: "USD" };
|
|
1035
|
-
if (format == MetadataFormats.CurrencyPound)
|
|
1036
|
-
return { type: 'currency', precision: 2, currency: "GBP" };
|
|
1037
|
-
if (format == MetadataFormats.CurrencyYen)
|
|
1038
|
-
return { type: 'currency', currency: "JPY" };
|
|
1171
|
+
// Formato e cultura di visualizzazione definiti sulle proprietà estese della colonna
|
|
1172
|
+
const { format, formatCulture } = getColumnFormatInfo(col);
|
|
1173
|
+
// Date: la griglia passa al formatter un oggetto Date già istanziato
|
|
1174
|
+
if (col.dataType === DataColumnTypes.DateTime)
|
|
1175
|
+
return { formatter: (value) => formatDateTimeByMetadataFormat(value, format, formatCulture) };
|
|
1176
|
+
// Numeri (incluse valute): stessa formattazione usata da TMRelationViewer
|
|
1177
|
+
if (col.dataType === DataColumnTypes.Number)
|
|
1178
|
+
return { formatter: (value) => formatNumberByMetadataFormat(value, format, formatCulture) };
|
|
1039
1179
|
return undefined;
|
|
1040
1180
|
}, []);
|
|
1041
1181
|
/**
|
|
@@ -1140,6 +1280,57 @@ const TMSearchResultGrid = ({ openInOffice, fromDTD, operationItems, allUsers, i
|
|
|
1140
1280
|
});
|
|
1141
1281
|
return cols;
|
|
1142
1282
|
}, [searchResult, dataType, cellRender, getDisplayFormat, dataListsCache, usersCache]);
|
|
1283
|
+
/**
|
|
1284
|
+
* Colonne in cui il testo mostrato è diverso dal valore archiviato: date e numeri formattati, descrizioni
|
|
1285
|
+
* di liste dati e utenti. Su queste la ricerca della griglia va fatta sul testo mostrato, altrimenti non
|
|
1286
|
+
* trova nulla (es. cercando 29/01/2023 su una data, che nei dati è una stringa ISO).
|
|
1287
|
+
* Le cache sono ref lette al momento della ricerca: a quel punto sono già popolate.
|
|
1288
|
+
*/
|
|
1289
|
+
const searchTextGetters = useMemo(() => {
|
|
1290
|
+
const getters = new Map();
|
|
1291
|
+
const columnsOfResult = searchResult?.dtdResult?.columns;
|
|
1292
|
+
if (!columnsOfResult)
|
|
1293
|
+
return getters;
|
|
1294
|
+
const uniqueKeys = generateUniqueColumnKeys(columnsOfResult, searchResult?.fromTID);
|
|
1295
|
+
columnsOfResult.forEach((col, index) => {
|
|
1296
|
+
const dataField = uniqueKeys[index];
|
|
1297
|
+
if (!dataField)
|
|
1298
|
+
return;
|
|
1299
|
+
const dataDomain = MetadataDataDomains[(col.extendedProperties?.["DataDomain"] ?? "None")];
|
|
1300
|
+
const dataListID = Number(col.extendedProperties?.["DataListID"]);
|
|
1301
|
+
if (dataDomain === MetadataDataDomains.DataList && dataListID) {
|
|
1302
|
+
getters.set(dataField, (rowData) => getDataListItem(dataListID, rowData?.[dataField])?.name ?? String(rowData?.[dataField] ?? ''));
|
|
1303
|
+
return;
|
|
1304
|
+
}
|
|
1305
|
+
if (dataDomain === MetadataDataDomains.UserID) {
|
|
1306
|
+
getters.set(dataField, (rowData) => {
|
|
1307
|
+
const rawValue = rowData?.[dataField];
|
|
1308
|
+
// Un campo utente vuoto non mostra nulla: senza questo controllo Number('') darebbe 0, cioè l'utente di sistema
|
|
1309
|
+
if (rawValue === undefined || rawValue === null || rawValue === '')
|
|
1310
|
+
return '';
|
|
1311
|
+
const userId = Number(rawValue);
|
|
1312
|
+
if (Number.isNaN(userId))
|
|
1313
|
+
return String(rawValue);
|
|
1314
|
+
if (userId === 0)
|
|
1315
|
+
return SDKUI_Localizator.SystemUser ?? '';
|
|
1316
|
+
const ud = getUserItem(userId);
|
|
1317
|
+
return (ud ? getCompleteUserName(ud.domain, ud.name) : undefined) ?? String(rawValue);
|
|
1318
|
+
});
|
|
1319
|
+
return;
|
|
1320
|
+
}
|
|
1321
|
+
// Data e numero vengono mostrati con il formato definito sulle proprietà estese della colonna
|
|
1322
|
+
const { format, formatCulture } = getColumnFormatInfo(col);
|
|
1323
|
+
if (col.dataType === DataColumnTypes.DateTime) {
|
|
1324
|
+
getters.set(dataField, (rowData) => getDateDisplayText(rowData?.[dataField], format, formatCulture));
|
|
1325
|
+
return;
|
|
1326
|
+
}
|
|
1327
|
+
if (col.dataType === DataColumnTypes.Number) {
|
|
1328
|
+
getters.set(dataField, (rowData) => getNumberDisplayText(rowData?.[dataField], format, formatCulture));
|
|
1329
|
+
}
|
|
1330
|
+
});
|
|
1331
|
+
return getters;
|
|
1332
|
+
}, [searchResult, getDataListItem, getUserItem, getCompleteUserName]);
|
|
1333
|
+
const customizeColumns = useMemo(() => customizeSearchByDisplayText(searchTextGetters), [searchTextGetters]);
|
|
1143
1334
|
/**
|
|
1144
1335
|
* Effect che carica i dati necessari e genera le colonne della griglia.
|
|
1145
1336
|
* Esegue il caricamento delle cache (DataList e UserID) in parallelo prima di generare le colonne,
|
|
@@ -1209,6 +1400,14 @@ const TMSearchResultGrid = ({ openInOffice, fromDTD, operationItems, allUsers, i
|
|
|
1209
1400
|
let newDataSource = searchResultDescriptorToSimpleArray(searchResult);
|
|
1210
1401
|
setDataSource(newDataSource);
|
|
1211
1402
|
}, [lastUpdateSearchTime]);
|
|
1403
|
+
const gridSorting = useMemo(() => ({ mode: 'multiple' }), []);
|
|
1404
|
+
const gridSelection = useMemo(() => ({ mode: allowMultipleSelection ? 'multiple' : 'single' }), [allowMultipleSelection]);
|
|
1405
|
+
const useNativeScrollbar = SDKUI_Globals.userSettings?.themeSettings.gridSettings.useNativeScrollbar === 1;
|
|
1406
|
+
const gridScrolling = useMemo(() => ({
|
|
1407
|
+
columnRenderingMode: 'virtual',
|
|
1408
|
+
rowRenderingMode: 'standard',
|
|
1409
|
+
useNative: useNativeScrollbar
|
|
1410
|
+
}), [useNativeScrollbar]);
|
|
1212
1411
|
// Handles selection change in the data grid
|
|
1213
1412
|
const handleSelectionChange = useCallback((e) => {
|
|
1214
1413
|
if (onSelectionChanged === undefined)
|
|
@@ -1231,6 +1430,9 @@ const TMSearchResultGrid = ({ openInOffice, fromDTD, operationItems, allUsers, i
|
|
|
1231
1430
|
// Era sull'icona, non fare nulla
|
|
1232
1431
|
return;
|
|
1233
1432
|
}
|
|
1433
|
+
// Due click rapidi su un'icona della colonna azioni non devono aprire anche il form
|
|
1434
|
+
if (e.event?.target.closest('.tm-row-actions'))
|
|
1435
|
+
return;
|
|
1234
1436
|
// Verifica che il documento abbia TID e DID validi prima di procedere
|
|
1235
1437
|
if (!e.data.TID || !e.data.DID) {
|
|
1236
1438
|
ShowAlert({
|
|
@@ -1244,8 +1446,43 @@ const TMSearchResultGrid = ({ openInOffice, fromDTD, operationItems, allUsers, i
|
|
|
1244
1446
|
onFocusedItemChanged?.(e.data);
|
|
1245
1447
|
onDblClick();
|
|
1246
1448
|
}, [onDblClick]);
|
|
1449
|
+
/**
|
|
1450
|
+
* Colonna delle azioni di riga, in testa alla griglia (subito dopo la checkbox di selezione, che
|
|
1451
|
+
* DevExtreme tiene sempre per prima). Vive solo qui e non nello stato `columns`, che è quello
|
|
1452
|
+
* sincronizzato col padre per l'esportazione: una colonna senza dataField finirebbe in Excel come
|
|
1453
|
+
* colonna vuota.
|
|
1454
|
+
*
|
|
1455
|
+
* Le operazioni sono lette da una ref perché `operationItems` è ricostruito a ogni render del
|
|
1456
|
+
* padre: usarlo come dipendenza renderebbe nuova la colonna, e con essa `dataColumns`, ad ogni
|
|
1457
|
+
* giro. La cellRender le rilegge a ogni ridisegno della griglia, quindi resta comunque aggiornata.
|
|
1458
|
+
*/
|
|
1459
|
+
const operationItemsRef = useRef(operationItems);
|
|
1460
|
+
operationItemsRef.current = operationItems;
|
|
1461
|
+
const actionsColumn = useMemo(() => ({
|
|
1462
|
+
caption: '',
|
|
1463
|
+
width: 110,
|
|
1464
|
+
alignment: 'center',
|
|
1465
|
+
allowSorting: false,
|
|
1466
|
+
allowFiltering: false,
|
|
1467
|
+
allowHeaderFiltering: false,
|
|
1468
|
+
allowResizing: false,
|
|
1469
|
+
allowReordering: false,
|
|
1470
|
+
allowHiding: false,
|
|
1471
|
+
allowExporting: false,
|
|
1472
|
+
showInColumnChooser: false,
|
|
1473
|
+
cssClass: 'tm-row-actions',
|
|
1474
|
+
cellRender: (cellData) => (_jsx("div", { style: rowActionsStyles.cell, children: rowActions.map(action => {
|
|
1475
|
+
const operation = findOperationItemById(operationItemsRef.current, action.operationId);
|
|
1476
|
+
if (!operation || operation.visible === false)
|
|
1477
|
+
return null;
|
|
1478
|
+
if (action.isVisible && !action.isVisible(cellData.data))
|
|
1479
|
+
return null;
|
|
1480
|
+
return (_jsx("span", { style: rowActionsStyles.icon, title: operation.name, onClick: () => onRowActionRequest?.(action.operationId, cellData.data), children: action.icon }, action.operationId));
|
|
1481
|
+
}) })),
|
|
1482
|
+
}), [onRowActionRequest]);
|
|
1247
1483
|
const dataColumns = useMemo(() => {
|
|
1248
1484
|
return [
|
|
1485
|
+
...(showActionsColumn ? [actionsColumn] : []),
|
|
1249
1486
|
{
|
|
1250
1487
|
dataType: "object",
|
|
1251
1488
|
dataField: 'FILEEXT',
|
|
@@ -1259,7 +1496,7 @@ const TMSearchResultGrid = ({ openInOffice, fromDTD, operationItems, allUsers, i
|
|
|
1259
1496
|
},
|
|
1260
1497
|
...columns.filter(col => col.dataField !== 'FILEEXT')
|
|
1261
1498
|
];
|
|
1262
|
-
}, [columns, onDownloadDcmtsAsync, openInOffice]);
|
|
1499
|
+
}, [columns, onDownloadDcmtsAsync, openInOffice, showActionsColumn, actionsColumn]);
|
|
1263
1500
|
const onContentReady = useCallback((e) => {
|
|
1264
1501
|
if (e === undefined)
|
|
1265
1502
|
return;
|
|
@@ -1270,21 +1507,22 @@ const TMSearchResultGrid = ({ openInOffice, fromDTD, operationItems, allUsers, i
|
|
|
1270
1507
|
setVisibleItems(visibleData);
|
|
1271
1508
|
}, []);
|
|
1272
1509
|
useEffect(() => { onVisibleItemChanged?.(visibleItems); }, [visibleItems]);
|
|
1273
|
-
|
|
1510
|
+
const defaultCounterItems = dcmtsReturned !== undefined && dcmtsFound !== undefined
|
|
1511
|
+
? new Map([
|
|
1512
|
+
[CounterItemKey.allItems, {
|
|
1513
|
+
key: CounterItemKey.allItems,
|
|
1274
1514
|
show: true,
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
: undefined
|
|
1287
|
-
} })] });
|
|
1515
|
+
caption: `${dcmtsReturned} restituiti su ${dcmtsFound} trovati`,
|
|
1516
|
+
value: `${dcmtsReturned}/${dcmtsFound}`,
|
|
1517
|
+
icon: _jsx(IconAll, {}),
|
|
1518
|
+
order: -1
|
|
1519
|
+
}]
|
|
1520
|
+
])
|
|
1521
|
+
: undefined;
|
|
1522
|
+
const gridCounterConfig = showCounterConfig
|
|
1523
|
+
? { ...counterConfig, show: true, items: counterConfig?.items ?? defaultCounterItems }
|
|
1524
|
+
: { show: false };
|
|
1525
|
+
return _jsxs("div", { style: { width: "100%", height: "100%" }, children: [!isDataGridReady && (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', height: '100%', width: '100%', gap: '10px' }, children: [_jsx(LoadIndicator, { height: 60, width: 60 }), _jsx("div", { children: SDKUI_Localizator.Loading })] })), isDataGridReady && _jsx(TMDataGrid, { ref: dataGridRef, id: "tm-search-result", keyExpr: "rowIndex", dataColumns: dataColumns, dataSource: dataSource, customizeColumns: customizeColumns, repaintChangesOnly: true, selectedRowKeys: selectedRowKeys, focusedRowKey: disableAutoFocus ? undefined : Number(focusedItem?.rowIndex ?? 0), showSearchPanel: showSearchTMDatagrid, showFilterPanel: true, sorting: gridSorting, selection: gridSelection, scrolling: gridScrolling, pageSize: pageSize, compactPager: compactPager, onSelectionChanged: handleSelectionChange, onFocusedRowChanged: handleFocusedRowChange, onRowDblClick: onRowDblClick, onContentReady: onContentReady, showHeaderColumnChooser: true, onKeyDown: onKeyDown, customContextMenuItems: operationItems, counterConfig: gridCounterConfig })] });
|
|
1288
1526
|
};
|
|
1289
1527
|
//#region TMSearchResultSelector
|
|
1290
1528
|
const StyledItemTemplate = styled.div `
|
|
@@ -1345,14 +1583,29 @@ const TMSearchResultSelector = ({ searchResults = [], disableAccordionIfSingleCa
|
|
|
1345
1583
|
}
|
|
1346
1584
|
}
|
|
1347
1585
|
}, [sortedCategories.length, autoSelectFirst]);
|
|
1586
|
+
// La preselezione esterna va applicata una volta per valore: riapplicarla a ogni cambio di
|
|
1587
|
+
// searchResults faceva sì che un refresh annullasse la navigazione dell'utente.
|
|
1588
|
+
const appliedSelectedTIDRef = useRef(undefined);
|
|
1348
1589
|
useEffect(() => {
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1590
|
+
// Richiesta ritirata: dimentichiamo il valore applicato, così se il chiamante richiede di
|
|
1591
|
+
// nuovo lo stesso TID la preselezione riparte
|
|
1592
|
+
if (selectedTID === undefined) {
|
|
1593
|
+
appliedSelectedTIDRef.current = undefined;
|
|
1594
|
+
return;
|
|
1352
1595
|
}
|
|
1596
|
+
if (appliedSelectedTIDRef.current === selectedTID)
|
|
1597
|
+
return;
|
|
1598
|
+
const found = searchResults.find(r => Number(r.fromTID) === selectedTID);
|
|
1599
|
+
if (!found)
|
|
1600
|
+
return; // risultati non ancora arrivati: riproviamo al prossimo giro
|
|
1601
|
+
appliedSelectedTIDRef.current = selectedTID;
|
|
1602
|
+
handleSelect(found);
|
|
1353
1603
|
}, [selectedTID, searchResults]);
|
|
1354
|
-
|
|
1355
|
-
|
|
1604
|
+
// force = true per i click dell'utente: la selezione va notificata anche se il tipo documento è già quello selezionato
|
|
1605
|
+
const handleSelect = useCallback((result, force = false) => {
|
|
1606
|
+
if (result === undefined)
|
|
1607
|
+
return;
|
|
1608
|
+
if (selectedResult !== result || force) {
|
|
1356
1609
|
setSelectedResult(result);
|
|
1357
1610
|
onSelectionChanged?.(result);
|
|
1358
1611
|
}
|
|
@@ -1397,32 +1650,88 @@ const TMSearchResultSelector = ({ searchResults = [], disableAccordionIfSingleCa
|
|
|
1397
1650
|
renderItem: (result, isSelected) => (_jsxs("div", { style: { width: '100%', padding: '5px', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }, children: [_jsx(TMTidViewer, { tid: result.fromTID, did: Number(result.dtdResult?.rows?.[0]?.[1]), showIcon: true }), _jsx("div", { style: { padding: 3, display: 'flex', alignItems: 'center', justifyContent: 'center', backgroundColor: 'white', color: 'gray', borderRadius: 3 }, children: result.dcmtsReturned })] })),
|
|
1398
1651
|
itemHeight: 40
|
|
1399
1652
|
})), [sortedCategories, groupedResults, searchResults]);
|
|
1400
|
-
const renderCategoryItems = (category) => (_jsx("div", { style: { padding: '5px', height: '100%', overflow: 'auto' }, children: groupedResults[category].map((result, index) => (_jsx(MemoizedStyledItemTemplate, {
|
|
1653
|
+
const renderCategoryItems = (category) => (_jsx("div", { style: { padding: '5px', height: '100%', overflow: 'auto' }, children: groupedResults[category].map((result, index) => (_jsx(MemoizedStyledItemTemplate, { $isSelected: selectedResult === result, onClick: () => handleSelect(result, true), children: renderItemTemplate(result) }, index))) }));
|
|
1401
1654
|
if (disableAccordionIfSingleCategory && sortedCategories.length === 1) {
|
|
1402
1655
|
const category = sortedCategories[0];
|
|
1403
1656
|
return renderCategoryItems(category);
|
|
1404
1657
|
}
|
|
1405
|
-
return (_jsx(TMAccordionNew, { groups: accordionGroups, selectedItem: selectedResult, onSelectedItemChange: (result) => handleSelect(result) }));
|
|
1658
|
+
return (_jsx(TMAccordionNew, { groups: accordionGroups, selectedItem: selectedResult, onSelectedItemChange: (result) => handleSelect(result, true) }));
|
|
1406
1659
|
};
|
|
1407
1660
|
//#endregion TMSearchResultSelector
|
|
1408
|
-
|
|
1409
|
-
|
|
1661
|
+
/** Senza UI: vive dentro il provider e passa a onBack, via ref, l'azione "mostra il pannello lista". */
|
|
1662
|
+
const ShowMainPanelBridge = ({ showMainPanelRef }) => {
|
|
1663
|
+
const { setPanelVisibilityById } = useTMPanelManagerContext();
|
|
1410
1664
|
useEffect(() => {
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1665
|
+
// Su mobile mostrare un pannello nasconde gli altri; su desktop la lista è già visibile
|
|
1666
|
+
showMainPanelRef.current = () => setPanelVisibilityById('tmSearchResult', true);
|
|
1667
|
+
return () => { showMainPanelRef.current = null; };
|
|
1668
|
+
}, [setPanelVisibilityById, showMainPanelRef]);
|
|
1669
|
+
return null;
|
|
1670
|
+
};
|
|
1671
|
+
/** Senza UI: allinea i pannelli quando il layout viene salvato da un altro risultato di ricerca già aperto */
|
|
1672
|
+
const SavedLayoutSyncHandler = ({ disabledPanelIds }) => {
|
|
1673
|
+
const { panelVisibility, panelDimensions, maximizedPanels, isResizingActive, setPanelVisibilityById, setPanelDimensionsById } = useTMPanelManagerContext();
|
|
1674
|
+
// Il layout è condiviso fra i risultati aperti: si sottoscrive la firma, che è una stringa, perché
|
|
1675
|
+
// React confronta le letture per riferimento e su un oggetto ri-renderizzerebbe all'infinito
|
|
1676
|
+
const savedLayoutSignature = useSyncExternalStore(subscribeSearchResultPanelLayout, getSearchResultPanelLayoutSignature);
|
|
1677
|
+
useEffect(() => {
|
|
1678
|
+
// Con un pannello massimizzato o un separatore in movimento comanda l'utente di questa istanza
|
|
1679
|
+
if (maximizedPanels.length > 0 || isResizingActive)
|
|
1680
|
+
return;
|
|
1681
|
+
// Al mount panelVisibility è ancora vuota: lo stato iniziale lo applica il provider.
|
|
1682
|
+
// Un pannello disabilitato qui non va aperto, gli altri si allineano comunque
|
|
1683
|
+
const panelsToApply = Object.entries(getSearchResultPanelLayout())
|
|
1684
|
+
.filter(([id, state]) => panelVisibility[id] !== undefined && !(state?.visible && disabledPanelIds.includes(id)));
|
|
1685
|
+
panelsToApply.forEach(([id, state]) => {
|
|
1686
|
+
const isVisible = state?.visible ?? false;
|
|
1687
|
+
if (panelVisibility[id] !== isVisible)
|
|
1688
|
+
setPanelVisibilityById(id, isVisible);
|
|
1689
|
+
});
|
|
1690
|
+
// Le larghezze salvate valgono come pesi, non come percentuali: qui si normalizzano sui soli pannelli
|
|
1691
|
+
// che questo risultato apre davvero, così lo spazio di quelli scartati non resta vuoto
|
|
1692
|
+
const panelsToShow = panelsToApply.filter(([, state]) => state?.visible && parseFloat(state.width) > 0 && parseFloat(state.height) > 0);
|
|
1693
|
+
const weightTotal = panelsToShow.reduce((total, [, state]) => total + parseFloat(state.width), 0);
|
|
1694
|
+
if (weightTotal <= 0)
|
|
1695
|
+
return;
|
|
1696
|
+
// Dopo la visibilità, che accoda un suo ricalcolo delle quote: così restano quelle salvate.
|
|
1697
|
+
// Le quote sono arrotondate, altrimenti due risultati si rincorrono sugli ultimi decimali
|
|
1698
|
+
panelsToShow.forEach(([id, state]) => {
|
|
1699
|
+
const width = `${Math.round(parseFloat(state.width) / weightTotal * 10000) / 100}%`;
|
|
1700
|
+
if (panelDimensions[id]?.width === width && panelDimensions[id]?.height === state.height)
|
|
1701
|
+
return;
|
|
1702
|
+
setPanelDimensionsById(id, width, state.height);
|
|
1703
|
+
});
|
|
1704
|
+
}, [savedLayoutSignature]);
|
|
1705
|
+
return null;
|
|
1706
|
+
};
|
|
1707
|
+
const PanelDisabledStateHandler = ({ isBoardDisabled, savedBlogVisible = false }) => {
|
|
1708
|
+
const { panelVisibility, setPanelVisibilityById, setToolbarButtonDisabled } = useTMPanelManagerContext();
|
|
1709
|
+
const isBlogVisible = panelVisibility['tmBlog'] ?? false;
|
|
1710
|
+
useEffect(() => {
|
|
1711
|
+
setToolbarButtonDisabled('tmBlog', isBoardDisabled);
|
|
1418
1712
|
}, [isBoardDisabled]);
|
|
1713
|
+
/**
|
|
1714
|
+
* Senza bacheca nel tipo documento il pannello va chiuso ogni volta che ricompare, non solo al cambio
|
|
1715
|
+
* di stato: il layout salvato viene applicato dopo questo effetto e può riportarlo a video.
|
|
1716
|
+
* È un effetto di layout per chiuderlo prima che venga disegnato, altrimenti lampeggia.
|
|
1717
|
+
*/
|
|
1718
|
+
useLayoutEffect(() => {
|
|
1719
|
+
if (isBoardDisabled && isBlogVisible)
|
|
1720
|
+
setPanelVisibilityById('tmBlog', false);
|
|
1721
|
+
}, [isBoardDisabled, isBlogVisible]);
|
|
1722
|
+
// Bacheca di nuovo prevista: si riapre come da layout salvato. isBlogVisible non è fra le dipendenze,
|
|
1723
|
+
// altrimenti riaprirebbe il pannello appena chiuso dall'utente
|
|
1724
|
+
useEffect(() => {
|
|
1725
|
+
if (!isBoardDisabled && savedBlogVisible && !isBlogVisible)
|
|
1726
|
+
setPanelVisibilityById('tmBlog', true);
|
|
1727
|
+
}, [isBoardDisabled, savedBlogVisible]);
|
|
1419
1728
|
return null;
|
|
1420
1729
|
};
|
|
1421
|
-
const TMDcmtPreviewWrapper = ({ refreshPreviewTrigger, currentDcmt, isVisible, onBack }) => {
|
|
1730
|
+
const TMDcmtPreviewWrapper = ({ refreshPreviewTrigger, currentDcmt, isVisible, isPageVisible = true, onBack }) => {
|
|
1422
1731
|
const { setPanelVisibilityById, toggleMaximize, isResizingActive, countVisibleLeafPanels } = useTMPanelManagerContext();
|
|
1423
1732
|
const deviceType = useDeviceType();
|
|
1424
1733
|
const isMobile = deviceType === DeviceType.MOBILE;
|
|
1425
|
-
return (_jsx(TMDcmtPreview, { dcmtData: currentDcmt, onClosePanel: (!isMobile && countVisibleLeafPanels() > 1) ? () => setPanelVisibilityById('tmDcmtPreview', false) : undefined, onBack: onBack, allowMaximize: !isMobile && countVisibleLeafPanels() > 1, onMaximizePanel: (!isMobile && countVisibleLeafPanels() > 1) ? () => toggleMaximize("tmDcmtPreview") : undefined, isResizingActive: isResizingActive, isVisible: isVisible }, refreshPreviewTrigger));
|
|
1734
|
+
return (_jsx(TMDcmtPreview, { dcmtData: currentDcmt, onClosePanel: (!isMobile && countVisibleLeafPanels() > 1) ? () => setPanelVisibilityById('tmDcmtPreview', false) : undefined, onBack: onBack, allowMaximize: !isMobile && countVisibleLeafPanels() > 1, onMaximizePanel: (!isMobile && countVisibleLeafPanels() > 1) ? () => toggleMaximize("tmDcmtPreview") : undefined, isResizingActive: isResizingActive, isVisible: isVisible && isPageVisible }, refreshPreviewTrigger));
|
|
1426
1735
|
};
|
|
1427
1736
|
// Styled Components
|
|
1428
1737
|
const StyledPlaceholder = styled.div `
|