@topconsultnpm/sdkui-react 6.22.0-dev2.4 → 6.22.0-dev2.41
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 +11 -0
- package/lib/components/base/TMModal.js +47 -13
- 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/TMMergeToPdfForm.d.ts +1 -2
- package/lib/components/features/documents/TMMergeToPdfForm.js +30 -5
- package/lib/components/features/documents/TMMultiMasterDetailDcmtsForm.d.ts +45 -0
- package/lib/components/features/documents/TMMultiMasterDetailDcmtsForm.js +323 -0
- package/lib/components/features/documents/TMMultiMasterDetailDcmtsUtils.d.ts +370 -0
- package/lib/components/features/documents/TMMultiMasterDetailDcmtsUtils.js +283 -0
- package/lib/components/features/documents/TMRelationViewer.d.ts +14 -1
- package/lib/components/features/documents/TMRelationViewer.js +69 -20
- package/lib/components/features/search/TMSearch.js +31 -18
- package/lib/components/features/search/TMSearchQueryEditor.js +5 -3
- package/lib/components/features/search/TMSearchQueryPanel.d.ts +2 -1
- package/lib/components/features/search/TMSearchQueryPanel.js +45 -9
- package/lib/components/features/search/TMSearchResult.d.ts +15 -0
- package/lib/components/features/search/TMSearchResult.js +509 -187
- 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/devextreme-license.d.ts +1 -0
- package/lib/devextreme-license.js +3 -0
- package/lib/helper/SDKUI_Globals.d.ts +109 -0
- package/lib/helper/SDKUI_Globals.js +150 -0
- package/lib/helper/SDKUI_Localizator.d.ts +34 -0
- package/lib/helper/SDKUI_Localizator.js +340 -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 +4 -0
- package/lib/hooks/useDocumentOperations.js +41 -7
- package/lib/hooks/useMultiMasterDetailDcmts.d.ts +113 -0
- package/lib/hooks/useMultiMasterDetailDcmts.js +760 -0
- package/lib/hooks/useRelatedDocuments.js +2 -26
- package/lib/hooks/useShowDossiersV5.d.ts +12 -0
- package/lib/hooks/useShowDossiersV5.js +37 -0
- package/lib/hooks/useTMDistinctValuesMetadataDisplay.d.ts +18 -0
- package/lib/hooks/useTMDistinctValuesMetadataDisplay.js +103 -0
- package/lib/hooks/useTMDistinctValuesQuickSearch.d.ts +49 -0
- package/lib/hooks/useTMDistinctValuesQuickSearch.js +307 -0
- package/lib/hooks/useTMDistinctValuesSelection.d.ts +42 -0
- package/lib/hooks/useTMDistinctValuesSelection.js +103 -0
- package/lib/hooks/useTMDistinctValuesSource.d.ts +29 -0
- package/lib/hooks/useTMDistinctValuesSource.js +105 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.js +5 -2
- package/lib/services/caseflow/CaseFlowService.d.ts +236 -0
- package/lib/services/caseflow/CaseFlowService.js +693 -0
- package/lib/services/caseflow/CaseFlowTemplateCacheService.d.ts +28 -0
- package/lib/services/caseflow/CaseFlowTemplateCacheService.js +121 -0
- package/lib/services/caseflow/caseFlowNameCache.d.ts +32 -0
- package/lib/services/caseflow/caseFlowNameCache.js +116 -0
- package/lib/services/caseflow/caseFlowWorkItemUtils.d.ts +61 -0
- package/lib/services/caseflow/caseFlowWorkItemUtils.js +113 -0
- package/lib/services/index.d.ts +4 -0
- package/lib/services/index.js +4 -0
- package/lib/services/platform_services.d.ts +1 -1
- package/package.json +9 -5
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
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
5
|
import { AppModules, DataColumnTypes, DataListViewModes, DcmtTypeListCacheService, LayoutCacheService, LayoutModes, MetadataDataDomains, SDK_Globals, SystemMIDsAsNumber, UserListCacheService, } from '@topconsultnpm/sdk-ts';
|
|
6
|
-
import { deepCompare, formatDateTimeByMetadataFormat, formatNumberByMetadataFormat, generateUniqueColumnKeys, genUniqueId, getColumnFormatInfo, getSearchToolbarVisibility, IconAll, IconBoard, IconDcmtTypeSys, IconDelete, IconMenuVertical, IconPlatform, IconRefresh, IconSearchCheck, IconShow, isApprovalWorkflowView, isSign4TopEnabled, searchResultDescriptorToSimpleArray, searchResultToMetadataValues, SDKUI_Globals, SDKUI_Localizator } from '../../../helper';
|
|
6
|
+
import { customizeSearchByDisplayText, deepCompare, formatDateTimeByMetadataFormat, formatNumberByMetadataFormat, generateUniqueColumnKeys, genUniqueId, getColumnFormatInfo, getDateDisplayText, getNumberDisplayText, getSearchToolbarVisibility, IconAll, IconBoard, IconDcmtTypeSys, IconDelete, IconDuplicate, IconEdit, IconMenuVertical, IconPlatform, IconRefresh, IconSearchCheck, IconShow, isApprovalWorkflowView, isSign4TopEnabled, searchResultDescriptorToSimpleArray, searchResultToMetadataValues, 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';
|
|
@@ -23,7 +23,8 @@ import { StyledMultiViewPanel } from '../../base/Styled';
|
|
|
23
23
|
import { TMLayoutWaitingContainer } from '../../base/TMWaitPanel';
|
|
24
24
|
import TMMetadataValues from '../../editors/TMMetadataValues';
|
|
25
25
|
import TMTidViewer from '../../viewers/TMTidViewer';
|
|
26
|
-
import {
|
|
26
|
+
import { useTMPanelManagerContext } from '../../layout/panelManager/TMPanelManagerContext';
|
|
27
|
+
import { TMPanelManagerWithPersistenceProvider } from '../../layout/panelManager/TMPanelManagerWithPersistenceProvider';
|
|
27
28
|
import TMPanelManagerContainer from '../../layout/panelManager/TMPanelManagerContainer';
|
|
28
29
|
import TMContextMenu from '../../NewComponents/ContextMenu/TMContextMenu';
|
|
29
30
|
import TMToppyDraggableHelpCenter from '../assistant/TMToppyDraggableHelpCenter';
|
|
@@ -51,13 +52,25 @@ const orderByName = (array) => {
|
|
|
51
52
|
return 1;
|
|
52
53
|
} return 0; });
|
|
53
54
|
};
|
|
55
|
+
//#endregion Helper Methods
|
|
56
|
+
/**
|
|
57
|
+
* Contesti che ricordano il layout dei pannelli, condividendone uno solo.
|
|
58
|
+
* Gli altri sono esclusi di proposito: FREE_SEARCH ha un pannello in più, quindi il suo layout non vale
|
|
59
|
+
* per gli altri, e i restanti mostrano il risultato dentro contenitori con esigenze di spazio loro.
|
|
60
|
+
*/
|
|
61
|
+
const PERSISTED_LAYOUT_CONTEXTS = [
|
|
62
|
+
SearchResultContext.METADATA_SEARCH,
|
|
63
|
+
SearchResultContext.WORKFLOW_APPROVE,
|
|
64
|
+
];
|
|
54
65
|
const TMSearchResult = ({
|
|
55
66
|
// Data
|
|
56
67
|
groupId, searchResults = [], context = SearchResultContext.METADATA_SEARCH, title, selectedSearchResultTID, floatingActionConfig, workingGroupContext = undefined, inputDID,
|
|
57
68
|
// 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,
|
|
69
|
+
autoFocusFirstRow = true, formAutoOpen, isVisible = true, allowRelations = true, openDcmtFormAsModal = false, showSearchResultSidebar = true, showDcmtFormSidebar = true, showSelector = false, isClosable = false, allowFloatingBar = true, showToolbarHeader = true, showBackButton = true, 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,
|
|
70
|
+
// Counters
|
|
71
|
+
counterConfig,
|
|
59
72
|
// Callbacks (optional)
|
|
60
|
-
openInOffice, onRefreshAfterAddDcmtToFavs, onRefreshSearchAsyncDatagrid, onSelectedTIDChanged, onWFOperationCompleted, onClose, onFileOpened, onTaskCreateRequest, openWGsCopyMoveForm, openCommentFormCallback, openAddDocumentForm, onOpenS4TViewerRequest, onOpenPdfEditorRequest, openFileUploaderPdfEditor, passToArchiveCallback, onReferenceClick,
|
|
73
|
+
openInOffice, onRefreshAfterAddDcmtToFavs, onRefreshSearchAsyncDatagrid, onSelectedTIDChanged, onSelectedTIDCleared, onWFOperationCompleted, onClose, onFileOpened, onTaskCreateRequest, openWGsCopyMoveForm, openCommentFormCallback, openAddDocumentForm, onOpenS4TViewerRequest, onOpenPdfEditorRequest, openFileUploaderPdfEditor, passToArchiveCallback, onReferenceClick,
|
|
61
74
|
// Tasks
|
|
62
75
|
allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTaskCallback, editTaskCallback,
|
|
63
76
|
// Navigation
|
|
@@ -69,13 +82,19 @@ handleNavigateToWGs, handleNavigateToDossiers, fetchRemoteCertificates, graphome
|
|
|
69
82
|
// Quando l'utente seleziona manualmente, il ref viene settato a false e il focus automatico
|
|
70
83
|
// torna al comportamento normale.
|
|
71
84
|
const isFirstAutoFocusRef = useRef(true);
|
|
85
|
+
// Mostra il pannello lista. È una ref perché il TMPanelManagerProvider sta dentro al JSX di
|
|
86
|
+
// questo componente, quindi qui il context non si può usare: la riempie ShowMainPanelBridge.
|
|
87
|
+
const showMainPanelRef = useRef(null);
|
|
72
88
|
// ID state to force remount of components
|
|
73
89
|
const [id, setID] = useState('');
|
|
74
90
|
// Document type descriptor of the currently document
|
|
75
91
|
const [fromDTD, setFromDTD] = useState();
|
|
76
92
|
const [currentDcmt, setCurrentDcmt] = useState();
|
|
77
|
-
//
|
|
78
|
-
|
|
93
|
+
// Passo corrente. Su mobile decide anche quale pannello è a schermo (vedi isSteppedLayout).
|
|
94
|
+
// 'auto' -> l'utente non ha ancora scelto: si può selezionare il primo tipo documento
|
|
95
|
+
// 'selector' -> è tornato indietro col back: non selezionare niente al posto suo
|
|
96
|
+
// 'results' -> è sulla griglia del tipo scelto
|
|
97
|
+
const [navStep, setNavStep] = useState('auto');
|
|
79
98
|
// State to control the selected search result
|
|
80
99
|
const [selectedSearchResult, setSelectedSearchResult] = useState();
|
|
81
100
|
// State to control the search results to show in the datagrid
|
|
@@ -303,7 +322,7 @@ handleNavigateToWGs, handleNavigateToDossiers, fetchRemoteCertificates, graphome
|
|
|
303
322
|
createTaskFromDocumentOrWorkItem();
|
|
304
323
|
}
|
|
305
324
|
};
|
|
306
|
-
const { operationItems, renderFloatingBar, renderDcmtOperations, features, } = useDocumentOperations({
|
|
325
|
+
const { operationItems, selectedDcmtInfos, renderFloatingBar, renderDcmtOperations, features, } = useDocumentOperations({
|
|
307
326
|
context: context,
|
|
308
327
|
documentData: {
|
|
309
328
|
dtd: fromDTD,
|
|
@@ -377,9 +396,69 @@ handleNavigateToWGs, handleNavigateToDossiers, fetchRemoteCertificates, graphome
|
|
|
377
396
|
openTaskFormHandler,
|
|
378
397
|
},
|
|
379
398
|
});
|
|
380
|
-
const { isOpenDcmtForm, openFormHandler, dcmtFormLayoutMode, onDcmtFormOpenChange, showSearchTMDatagrid,
|
|
399
|
+
const { isOpenDcmtForm, isDcmtFormModal, openFormHandler, dcmtFormLayoutMode, onDcmtFormOpenChange, showSearchTMDatagrid, showDcmtTypesSelection, showExportForm, updateBatchUpdateForm, closeDcmtFormHandler, handleSignApprove, checkoutInfo: { showCicoWaitPanel, cicoWaitPanelTitle, showCicoPrimaryProgress, cicoPrimaryProgressText, cicoPrimaryProgressValue, cicoPrimaryProgressMax, }, dcmtOperations: { abortController, showWaitPanel, showPrimary, waitPanelTitle, waitPanelTextPrimary, waitPanelValuePrimary, waitPanelMaxValuePrimary, showSecondary, waitPanelTextSecondary, waitPanelValueSecondary, waitPanelMaxValueSecondary, downloadDcmtsAsync, runOperationAsync, }, relatedDocumentsInfo: { isOpenDetails, isOpenMaster, checkRelatedDcmtsArchiveCapability, checkManyToManyCapability, }, toppyOperations: { showApprovePopup, showRejectPopup, showReAssignPopup, showMoreInfoPopup, updateShowApprovePopup, updateShowRejectPopup, updateShowReAssignPopup, updateShowMoreInfoPopup } } = features;
|
|
400
|
+
// ----- Azioni della colonna di riga (showActionsColumn) -----------------------------------------
|
|
401
|
+
// Le voci di operationItems agiscono sui documenti selezionati o, in mancanza, su quello a fuoco:
|
|
402
|
+
// non accettano una riga come argomento. Il click sull'icona quindi azzera la selezione e porta il
|
|
403
|
+
// fuoco sulla riga cliccata, poi attende. L'attesa non è sul fuoco ma su selectedDcmtInfos, che
|
|
404
|
+
// l'hook ricalcola in un effect (un render più tardi): lanciare l'operazione prima significherebbe
|
|
405
|
+
// eseguirla sulla riga precedente.
|
|
406
|
+
const pendingRowActionRef = useRef(undefined);
|
|
407
|
+
// La callback è letta da una ref: dipendere dal prop renderebbe nuova requestRowAction, e con essa
|
|
408
|
+
// la colonna delle azioni, a ogni render del padre (vedi actionsColumn in TMSearchResultGrid)
|
|
409
|
+
const onRowDuplicateRequestRef = useRef(onRowDuplicateRequest);
|
|
410
|
+
onRowDuplicateRequestRef.current = onRowDuplicateRequest;
|
|
411
|
+
const requestRowAction = useCallback((operationId, rowData) => {
|
|
412
|
+
if (!showActionsColumn)
|
|
413
|
+
return;
|
|
414
|
+
if (rowData?.TID === undefined || rowData?.DID === undefined) {
|
|
415
|
+
ShowAlert({ message: SDKUI_Localizator.InvalidDcmt, mode: "warning", duration: 3000 });
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
418
|
+
// Duplica ridefinita dal chiamante: agisce sulla riga cliccata, senza toccare fuoco e selezione
|
|
419
|
+
if (operationId === 'dup' && onRowDuplicateRequestRef.current) {
|
|
420
|
+
onRowDuplicateRequestRef.current(rowData);
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
pendingRowActionRef.current = { operationId, TID: rowData.TID, DID: rowData.DID };
|
|
424
|
+
isFirstAutoFocusRef.current = false;
|
|
425
|
+
setSelectedItems([]);
|
|
426
|
+
setFocusedItem(rowData);
|
|
427
|
+
}, [showActionsColumn]);
|
|
428
|
+
// La richiesta viene scartata se il documento sparisce dai risultati (es. refresh dopo
|
|
429
|
+
// un'eliminazione): senza questo resterebbe appesa e partirebbe al prossimo cambio di fuoco.
|
|
430
|
+
useEffect(() => { pendingRowActionRef.current = undefined; }, [selectedSearchResult, lastUpdateSearchTime]);
|
|
431
|
+
useEffect(() => {
|
|
432
|
+
if (!showActionsColumn)
|
|
433
|
+
return;
|
|
434
|
+
const pending = pendingRowActionRef.current;
|
|
435
|
+
if (!pending)
|
|
436
|
+
return;
|
|
437
|
+
// L'hook non ha ancora recepito la riga richiesta: si riproverà al prossimo aggiornamento
|
|
438
|
+
if (selectedDcmtInfos.length !== 1)
|
|
439
|
+
return;
|
|
440
|
+
if (selectedDcmtInfos[0].TID !== pending.TID || selectedDcmtInfos[0].DID !== pending.DID)
|
|
441
|
+
return;
|
|
442
|
+
pendingRowActionRef.current = undefined;
|
|
443
|
+
const operation = findOperationItemById(operationItems, pending.operationId);
|
|
444
|
+
// Ora che il fuoco è sulla riga, `disabled` riflette i permessi per quel documento
|
|
445
|
+
if (!operation || operation.disabled || operation.visible === false)
|
|
446
|
+
return;
|
|
447
|
+
operation.onClick?.();
|
|
448
|
+
}, [showActionsColumn, selectedDcmtInfos, operationItems]);
|
|
381
449
|
const deviceType = useDeviceType();
|
|
382
450
|
const isMobile = deviceType === DeviceType.MOBILE;
|
|
451
|
+
const hasSingleDcmtType = currentSearchResults.length === 1;
|
|
452
|
+
// Su mobile si vede un pannello per volta; su desktop selettore e griglia sono affiancati
|
|
453
|
+
const isSteppedLayout = showSelector && isMobile;
|
|
454
|
+
// Un solo tipo documento su desktop: non c'è niente da scegliere, quindi il selettore sparisce
|
|
455
|
+
// (larghezza 0, nessun separatore) e lo spazio va tutto alla griglia. Il menu "Altro" permette
|
|
456
|
+
// di riaprirlo (vedi canToggleDcmtTypesSelection nell'hook).
|
|
457
|
+
const isSelectorCollapsed = showSelector && !isSteppedLayout && hasSingleDcmtType && !showDcmtTypesSelection;
|
|
458
|
+
// Senza selettore lo spazio va tutto alla griglia; altrimenti a step su mobile, affiancati su desktop
|
|
459
|
+
const splitterSizes = (!showSelector || isSelectorCollapsed) ? ['0%', '100%']
|
|
460
|
+
: isSteppedLayout ? (navStep === 'results' ? ['0', '100%'] : ['100%', '0'])
|
|
461
|
+
: ['30%', '70%'];
|
|
383
462
|
const selectedDocs = getSelectedDcmtsOrFocused(selectedItems, focusedItem);
|
|
384
463
|
// Disable the "Sign/Approve" button if:
|
|
385
464
|
// 1. No document or multiple documents are selected, OR
|
|
@@ -400,8 +479,14 @@ handleNavigateToWGs, handleNavigateToDossiers, fetchRemoteCertificates, graphome
|
|
|
400
479
|
setSelectedSearchResult(undefined);
|
|
401
480
|
return;
|
|
402
481
|
}
|
|
482
|
+
// Un solo tipo documento: selezionalo e vai ai risultati, a meno che l'utente sia tornato indietro
|
|
403
483
|
if (searchResults.length === 1) {
|
|
484
|
+
if (navStep === 'selector') {
|
|
485
|
+
setSelectedSearchResult(undefined);
|
|
486
|
+
return;
|
|
487
|
+
}
|
|
404
488
|
setSelectedSearchResult(searchResults[0]);
|
|
489
|
+
setNavStep('results');
|
|
405
490
|
return;
|
|
406
491
|
}
|
|
407
492
|
// Se il TID precedentemente selezionato esiste ancora nei nuovi risultati, mantienilo.
|
|
@@ -415,6 +500,11 @@ handleNavigateToWGs, handleNavigateToDossiers, fetchRemoteCertificates, graphome
|
|
|
415
500
|
return;
|
|
416
501
|
}
|
|
417
502
|
}
|
|
503
|
+
// L'utente è sul selettore
|
|
504
|
+
if (isMobile && navStep !== 'results') {
|
|
505
|
+
setSelectedSearchResult(undefined);
|
|
506
|
+
return;
|
|
507
|
+
}
|
|
418
508
|
// Altrimenti seleziona il primo risultato ordinato
|
|
419
509
|
setSelectedSearchResult(orderByName(searchResults)[0]);
|
|
420
510
|
}, [searchResults]);
|
|
@@ -471,7 +561,9 @@ handleNavigateToWGs, handleNavigateToDossiers, fetchRemoteCertificates, graphome
|
|
|
471
561
|
return;
|
|
472
562
|
if (focusedItem?.DID != inputDID)
|
|
473
563
|
return;
|
|
474
|
-
|
|
564
|
+
if (focusedItem?.TID === undefined)
|
|
565
|
+
return;
|
|
566
|
+
onDcmtFormOpenChange(true, LayoutModes.Update);
|
|
475
567
|
}, [inputDID, formAutoOpen, focusedItem]);
|
|
476
568
|
// Quando openS4TViewer è true, apri automaticamente il viewer S4T
|
|
477
569
|
useEffect(() => {
|
|
@@ -531,47 +623,75 @@ handleNavigateToWGs, handleNavigateToDossiers, fetchRemoteCertificates, graphome
|
|
|
531
623
|
let counters = (showSelector && disableAccordionIfSingleCategory && searchResults.length > 1) ? getSearchResultCountersSingleCategory(searchResults) : "";
|
|
532
624
|
if (title)
|
|
533
625
|
return title + counters;
|
|
534
|
-
|
|
626
|
+
// Nome del tipo documento selezionato, accodato al titolo
|
|
627
|
+
const selectedDcmtTypeName = selectedSearchResult?.fromName ?? (searchResults?.length === 1 ? searchResults[0]?.fromName : undefined);
|
|
628
|
+
const withSelectedDcmtTypeName = (baseTitle) => selectedDcmtTypeName ? `${baseTitle} - ${selectedDcmtTypeName}` : baseTitle;
|
|
629
|
+
let titleHeader = withSelectedDcmtTypeName('Ricerca per metadati');
|
|
535
630
|
switch (context) {
|
|
536
631
|
case SearchResultContext.MASTER_DETAIL:
|
|
537
632
|
case SearchResultContext.METADATA_SEARCH:
|
|
538
633
|
titleHeader = `${searchResults?.length > 1 ? selectedSearchResult?.fromName ?? 'Ricerca per metadati' : searchResults[0]?.fromName ?? 'Ricerca per metadati'}`;
|
|
539
634
|
break;
|
|
540
635
|
case SearchResultContext.FAVORITES_AND_RECENTS:
|
|
541
|
-
titleHeader = SDKUI_Localizator.FavoritesAndRecentDcmts;
|
|
636
|
+
titleHeader = withSelectedDcmtTypeName(SDKUI_Localizator.FavoritesAndRecentDcmts);
|
|
542
637
|
break;
|
|
543
638
|
case SearchResultContext.WORKFLOW_APPROVE:
|
|
544
|
-
titleHeader = SDKUI_Localizator.WorkflowApproval;
|
|
639
|
+
titleHeader = withSelectedDcmtTypeName(SDKUI_Localizator.WorkflowApproval);
|
|
545
640
|
break;
|
|
546
641
|
case SearchResultContext.FREE_SEARCH:
|
|
547
|
-
titleHeader =
|
|
642
|
+
titleHeader = withSelectedDcmtTypeName('Risultato della ricerca full text');
|
|
548
643
|
break;
|
|
549
644
|
}
|
|
550
645
|
return titleHeader + counters;
|
|
551
646
|
};
|
|
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?.();
|
|
647
|
+
// Dai risultati si risale al selettore dei tipi documento
|
|
648
|
+
const canGoBackToSelector = isSteppedLayout && navStep === 'results' && selectedSearchResult !== undefined;
|
|
649
|
+
/**
|
|
650
|
+
* Back di tutti i pannelli (e X di chiusura se isClosable). Su mobile risale un livello alla volta:
|
|
651
|
+
* pannello secondario -> lista dei risultati -> selettore dei tipi documento -> uscita.
|
|
652
|
+
* Su desktop i pannelli sono affiancati, quindi resta solo l'uscita.
|
|
653
|
+
*
|
|
654
|
+
* @param fromSecondaryPanel - true se il back arriva da un pannello secondario
|
|
655
|
+
*/
|
|
656
|
+
const onBack = useCallback((fromSecondaryPanel = false) => {
|
|
657
|
+
// Non è previsto nessun modo di uscire: non fare niente
|
|
658
|
+
if (!showBackButton && !isClosable)
|
|
659
|
+
return;
|
|
660
|
+
// Torna alla lista senza toccare gli stati: l'utente deve ritrovare la sua selezione
|
|
661
|
+
if (fromSecondaryPanel) {
|
|
662
|
+
showMainPanelRef.current?.();
|
|
663
|
+
return;
|
|
573
664
|
}
|
|
574
|
-
|
|
665
|
+
// Sia il ritorno al selettore sia l'uscita ripartono da una lista pulita
|
|
666
|
+
setSelectedSearchResult(undefined);
|
|
667
|
+
setFocusedItem(undefined);
|
|
668
|
+
setSelectedItems([]);
|
|
669
|
+
setSelectedRowKeysFromDataGrid([]);
|
|
670
|
+
setCurrentDcmt(undefined);
|
|
671
|
+
setCurrentMetadataValues([]);
|
|
672
|
+
setShowIndexingInfo(false);
|
|
673
|
+
isFirstAutoFocusRef.current = true;
|
|
674
|
+
// Il chiamante può tenere allineato il suo TID selezionato (es. selectedSearchResultTID)
|
|
675
|
+
onSelectedTIDCleared?.();
|
|
676
|
+
// [2] l'utente ha chiesto la lista: resta lì finché non sceglie lui, niente auto-selezione.
|
|
677
|
+
// [1] si esce: si riparte da capo, quindi l'auto-selezione torna permessa.
|
|
678
|
+
setNavStep(canGoBackToSelector ? 'selector' : 'auto');
|
|
679
|
+
// [2] C'è ancora un livello sopra: restiamo dentro, sul selettore
|
|
680
|
+
if (canGoBackToSelector)
|
|
681
|
+
return;
|
|
682
|
+
// [1] Si esce e si avvisa il chiamante
|
|
683
|
+
onClose?.();
|
|
684
|
+
}, [canGoBackToSelector, showBackButton, isClosable, onClose, onSelectedTIDCleared]);
|
|
685
|
+
/**
|
|
686
|
+
* Back del pannello lista. `undefined` = freccia non renderizzata, quindi la mostriamo solo se
|
|
687
|
+
* ha dove tornare: uno step intermedio, o un onClose per uscire. Con `isClosable` basta la X.
|
|
688
|
+
*/
|
|
689
|
+
const backHandler = (showBackButton && !isClosable && (canGoBackToSelector || onClose !== undefined)) ? onBack : undefined;
|
|
690
|
+
/**
|
|
691
|
+
* Back dei pannelli secondari: la stessa onBack marcata come livello [3]. Solo su mobile:
|
|
692
|
+
* su desktop stanno affiancati alla lista e non c'è niente da cui tornare.
|
|
693
|
+
*/
|
|
694
|
+
const backHandlerSecondary = useMemo(() => (isMobile && backHandler) ? () => backHandler(true) : undefined, [isMobile, backHandler]);
|
|
575
695
|
const refreshDataGridAfterRemoveAsync = async () => {
|
|
576
696
|
let index = selectedSearchResult?.dtdResult?.columns?.findIndex(col => col.caption === 'DID');
|
|
577
697
|
let selectedRows = [];
|
|
@@ -603,21 +723,6 @@ handleNavigateToWGs, handleNavigateToDossiers, fetchRemoteCertificates, graphome
|
|
|
603
723
|
return newResults;
|
|
604
724
|
});
|
|
605
725
|
};
|
|
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
726
|
const removeDcmtFromFavsOrRecents = async () => {
|
|
622
727
|
switch (selectedSearchResult?.category) {
|
|
623
728
|
case "Favorites":
|
|
@@ -634,9 +739,9 @@ handleNavigateToWGs, handleNavigateToDossiers, fetchRemoteCertificates, graphome
|
|
|
634
739
|
};
|
|
635
740
|
const onSearchResultSelectionChanged = (e) => {
|
|
636
741
|
setSelectedSearchResult(e);
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
742
|
+
// Scelto il tipo documento si passa ai risultati (a livello di layout è ignorato se i due
|
|
743
|
+
// step sono affiancati, ma vale comunque come "l'utente non è più fermo sul selettore")
|
|
744
|
+
setNavStep('results');
|
|
640
745
|
onSelectedTIDChanged?.(e.fromTID);
|
|
641
746
|
};
|
|
642
747
|
const showToppyForApprove = useMemo(() => {
|
|
@@ -660,14 +765,15 @@ handleNavigateToWGs, handleNavigateToDossiers, fetchRemoteCertificates, graphome
|
|
|
660
765
|
&& !showTodoDcmtForm);
|
|
661
766
|
}, [showToppyForApprove, showToppyDraggableHelpCenter, selectedDocs, showApprovePopup, showRejectPopup, showReAssignPopup, showMoreInfoPopup, editPdfForm, openS4TViewer, showTodoDcmtForm]);
|
|
662
767
|
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: onRefreshSearchAsyncDatagrid }), _jsx(TMContextMenu, { items: operationItems, trigger: "left", children: _jsx(IconMenuVertical, { color: 'white', cursor: 'pointer' }) })
|
|
768
|
+
_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: onRefreshSearchAsyncDatagrid }), _jsx(TMContextMenu, { items: operationItems, trigger: "left", children: _jsx(IconMenuVertical, { color: 'white', cursor: 'pointer' }) }), showToolbarCloseButton && onClose &&
|
|
769
|
+
_jsx(TMButton, { btnStyle: 'icon', icon: _jsx(IconCloseOutline, { color: 'white' }), caption: SDKUI_Localizator.Close, onClick: onClose })] });
|
|
664
770
|
const tmSearchResult = useMemo(() => (!searchResults || searchResults.length <= 0)
|
|
665
771
|
? _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
772
|
:
|
|
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 ||
|
|
773
|
+
_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 && !isSteppedLayout && !isSelectorCollapsed, start: splitterSizes, children: [showSelector ?
|
|
774
|
+
_jsx(TMLayoutItem, { children: _jsx(TMSearchResultSelector, { searchResults: currentSearchResults, disableAccordionIfSingleCategory: disableAccordionIfSingleCategory, selectedTID: selectedSearchResultTID, selectedSearchResult: selectedSearchResult, autoSelectFirst: !isMobile || hasSingleDcmtType, onSelectionChanged: onSearchResultSelectionChanged }) })
|
|
669
775
|
:
|
|
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: () => {
|
|
776
|
+
_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
777
|
updateShowApprovePopup(true);
|
|
672
778
|
}, onSignApprove: () => {
|
|
673
779
|
handleSignApprove();
|
|
@@ -687,7 +793,6 @@ handleNavigateToWGs, handleNavigateToDossiers, fetchRemoteCertificates, graphome
|
|
|
687
793
|
showApprovePopup,
|
|
688
794
|
showRejectPopup,
|
|
689
795
|
showReAssignPopup,
|
|
690
|
-
isOpenBatchUpdate,
|
|
691
796
|
isOpenDetails,
|
|
692
797
|
isOpenMaster,
|
|
693
798
|
isOpenDcmtForm,
|
|
@@ -698,6 +803,10 @@ handleNavigateToWGs, handleNavigateToDossiers, fetchRemoteCertificates, graphome
|
|
|
698
803
|
openS4TViewer,
|
|
699
804
|
showBackButton,
|
|
700
805
|
isMobile,
|
|
806
|
+
navStep,
|
|
807
|
+
isSteppedLayout,
|
|
808
|
+
isSelectorCollapsed,
|
|
809
|
+
currentSearchResults,
|
|
701
810
|
currentMetadataValues,
|
|
702
811
|
onRefreshSearchAsyncDatagrid,
|
|
703
812
|
handleNavigateToWGs,
|
|
@@ -705,9 +814,14 @@ handleNavigateToWGs, handleNavigateToDossiers, fetchRemoteCertificates, graphome
|
|
|
705
814
|
editPdfForm,
|
|
706
815
|
showNoDcmtFoundMessage
|
|
707
816
|
]);
|
|
708
|
-
|
|
817
|
+
/**
|
|
818
|
+
* Il risultato è davvero a video: le pagine restano montate anche in secondo piano, e senza questo
|
|
819
|
+
* bacheca e anteprima scaricherebbero il documento fuori campo.
|
|
820
|
+
*/
|
|
821
|
+
const isSearchResultOnScreen = isVisible && !isOpenDcmtForm && !isOpenDetails && !isOpenMaster;
|
|
822
|
+
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
823
|
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:
|
|
824
|
+
const tmDcmtPreview = useMemo(() => _jsx(TMDcmtPreviewWrapper, { refreshPreviewTrigger: refreshPreviewTrigger, currentDcmt: currentDcmt, isPageVisible: isSearchResultOnScreen, onBack: backHandlerSecondary }), [currentDcmt, refreshPreviewTrigger, isSearchResultOnScreen, backHandlerSecondary]);
|
|
711
825
|
// Auto-fetch indexing info when drawer is open and focusedItem changes
|
|
712
826
|
useEffect(() => {
|
|
713
827
|
if (!focusedItem || !showIndexingInfo)
|
|
@@ -764,6 +878,22 @@ handleNavigateToWGs, handleNavigateToDossiers, fetchRemoteCertificates, graphome
|
|
|
764
878
|
}
|
|
765
879
|
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
880
|
}, [selectedSearchResult, focusedItem, indexingInfo, showIndexingInfo, loadingIndexingInfo]);
|
|
881
|
+
/**
|
|
882
|
+
* Su mobile i pannelli si mostrano uno per volta, quindi il layout non va ricordato; con groupId
|
|
883
|
+
* i pannelli sono di un panel manager esterno, che ha un layout suo. Senza la barra laterale
|
|
884
|
+
* l'utente non può aprire/chiudere i pannelli: non ha senso applicargli il layout salvato (li
|
|
885
|
+
* troverebbe aperti senza poterli chiudere) né lasciargli sporcare quello condiviso.
|
|
886
|
+
* Il layout salvato vale solo per il login con Surfer: gli altri moduli hanno layout propri.
|
|
887
|
+
*/
|
|
888
|
+
const isLayoutPersisted = SDK_Globals.tmSession?.SessionDescr?.appModuleID === AppModules.SURFER && !isMobile && !groupId?.length && showSearchResultSidebar && PERSISTED_LAYOUT_CONTEXTS.includes(context);
|
|
889
|
+
/**
|
|
890
|
+
* Pannelli che questo risultato non può mostrare (la bacheca è l'unico, vedi PanelDisabledStateHandler).
|
|
891
|
+
* Il layout è condiviso con gli altri risultati aperti: qui non vanno aperti quando il layout lo chiede,
|
|
892
|
+
* e il loro stato salvato non va toccato, altrimenti li si chiuderebbe dove invece sono attivi.
|
|
893
|
+
*/
|
|
894
|
+
const disabledLayoutPanelIds = isBoardDisabled ? ['tmBlog'] : [];
|
|
895
|
+
/** Bacheca aperta nel layout salvato: da riaprire quando il tipo documento torna a prevederla */
|
|
896
|
+
const savedBlogVisible = isLayoutPersisted && (getSearchResultPanelLayout()['tmBlog']?.visible ?? false);
|
|
767
897
|
const allInitialPanelVisibility = {
|
|
768
898
|
'tmSearchResult': true,
|
|
769
899
|
'tmBlog': false,
|
|
@@ -786,9 +916,10 @@ handleNavigateToWGs, handleNavigateToDossiers, fetchRemoteCertificates, graphome
|
|
|
786
916
|
component: tmSearchResult,
|
|
787
917
|
panelContainer: {
|
|
788
918
|
title: getTitleHeader(),
|
|
919
|
+
enableTitleMarquee: true,
|
|
789
920
|
showHeader: showToolbarHeader,
|
|
790
921
|
allowMaximize: !isMobile,
|
|
791
|
-
onBack:
|
|
922
|
+
onBack: backHandler,
|
|
792
923
|
onClose: isClosable ? onBack : undefined,
|
|
793
924
|
toolbar: searchResutlToolbar
|
|
794
925
|
},
|
|
@@ -803,7 +934,7 @@ handleNavigateToWGs, handleNavigateToDossiers, fetchRemoteCertificates, graphome
|
|
|
803
934
|
panelContainer: {
|
|
804
935
|
title: SDKUI_Localizator.BlogCase,
|
|
805
936
|
allowMaximize: !isMobile,
|
|
806
|
-
onBack:
|
|
937
|
+
onBack: backHandlerSecondary,
|
|
807
938
|
}
|
|
808
939
|
},
|
|
809
940
|
toolbarOptions: { icon: _jsx(IconBoard, { fontSize: 24 }), visible: getSearchToolbarVisibility(SDK_Globals.tmSession?.SessionDescr?.appModuleID ?? AppModules.SURFER).tmBlog, orderNumber: 2, isActive: allInitialPanelVisibility['tmBlog'] }
|
|
@@ -816,7 +947,7 @@ handleNavigateToWGs, handleNavigateToDossiers, fetchRemoteCertificates, graphome
|
|
|
816
947
|
panelContainer: {
|
|
817
948
|
title: SDKUI_Localizator.MetadataSystem,
|
|
818
949
|
allowMaximize: !isMobile,
|
|
819
|
-
onBack:
|
|
950
|
+
onBack: backHandlerSecondary,
|
|
820
951
|
}
|
|
821
952
|
},
|
|
822
953
|
toolbarOptions: { icon: _jsx(IconDcmtTypeSys, { fontSize: 24 }), visible: getSearchToolbarVisibility(SDK_Globals.tmSession?.SessionDescr?.appModuleID ?? AppModules.SURFER).tmSysMetadata, orderNumber: 3, isActive: allInitialPanelVisibility['tmSysMetadata'] }
|
|
@@ -830,7 +961,7 @@ handleNavigateToWGs, handleNavigateToDossiers, fetchRemoteCertificates, graphome
|
|
|
830
961
|
panelContainer: {
|
|
831
962
|
title: SDKUI_Localizator.ResultDetails,
|
|
832
963
|
allowMaximize: !isMobile,
|
|
833
|
-
onBack:
|
|
964
|
+
onBack: backHandlerSecondary,
|
|
834
965
|
}
|
|
835
966
|
},
|
|
836
967
|
toolbarOptions: { icon: _jsx(IconPlatform, { fontSize: 20 }), visible: getSearchToolbarVisibility(SDK_Globals.tmSession?.SessionDescr?.appModuleID ?? AppModules.SURFER).tmFullTextSearch, orderNumber: 4, isActive: allInitialPanelVisibility['tmFullTextSearch'] }
|
|
@@ -844,21 +975,49 @@ handleNavigateToWGs, handleNavigateToDossiers, fetchRemoteCertificates, graphome
|
|
|
844
975
|
},
|
|
845
976
|
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
977
|
}
|
|
847
|
-
], [tmSearchResult, tmBlog, tmSysMetadata, tmDcmtPreview, tmFullTextSearch, showToolbarHeader, context, isMobile]);
|
|
848
|
-
|
|
978
|
+
], [tmSearchResult, tmBlog, tmSysMetadata, tmDcmtPreview, tmFullTextSearch, showToolbarHeader, context, isMobile, backHandler, backHandlerSecondary, isClosable, onBack]);
|
|
979
|
+
/** Contenuto del panel manager: con groupId sta nel provider del contenitore, altrimenti in quello qui sotto */
|
|
980
|
+
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 })] }));
|
|
981
|
+
return (_jsxs(StyledMultiViewPanel, { "$isVisible": isVisible, children: [_jsx(StyledMultiViewPanel, { "$isVisible": (!isOpenDcmtForm || isDcmtFormModal) && !isOpenDetails && !isOpenMaster, style: {
|
|
849
982
|
display: 'flex',
|
|
850
983
|
flexDirection: isMobile ? 'column' : 'row',
|
|
851
984
|
justifyContent: 'space-between',
|
|
852
985
|
gap: Gutters.getGutters(),
|
|
853
986
|
width: '100%',
|
|
854
987
|
height: '100%',
|
|
855
|
-
}, children: _jsx(TMLayoutWaitingContainer, { direction: 'vertical', showWaitPanel: showWaitPanel, showWaitPanelPrimary: showPrimary, showWaitPanelSecondary: showSecondary, waitPanelTitle: waitPanelTitle, waitPanelTextPrimary: waitPanelTextPrimary, waitPanelValuePrimary: waitPanelValuePrimary, waitPanelMaxValuePrimary: waitPanelMaxValuePrimary, waitPanelTextSecondary: waitPanelTextSecondary, waitPanelValueSecondary: waitPanelValueSecondary, waitPanelMaxValueSecondary: waitPanelMaxValueSecondary, isCancelable: true, abortController: abortController, children: _jsx(TMLayoutWaitingContainer, { direction: 'vertical', showWaitPanel: showCicoWaitPanel, showWaitPanelPrimary: showCicoPrimaryProgress, waitPanelTitle: cicoWaitPanelTitle, waitPanelTextPrimary: cicoPrimaryProgressText, waitPanelValuePrimary: cicoPrimaryProgressValue, waitPanelMaxValuePrimary: cicoPrimaryProgressMax, isCancelable: true, abortController: abortControllerLocal, children: (groupId && groupId.length > 0) ?
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
988
|
+
}, children: _jsx(TMLayoutWaitingContainer, { direction: 'vertical', showWaitPanel: showWaitPanel, showWaitPanelPrimary: showPrimary, showWaitPanelSecondary: showSecondary, waitPanelTitle: waitPanelTitle, waitPanelTextPrimary: waitPanelTextPrimary, waitPanelValuePrimary: waitPanelValuePrimary, waitPanelMaxValuePrimary: waitPanelMaxValuePrimary, waitPanelTextSecondary: waitPanelTextSecondary, waitPanelValueSecondary: waitPanelValueSecondary, waitPanelMaxValueSecondary: waitPanelMaxValueSecondary, isCancelable: true, abortController: abortController, children: _jsx(TMLayoutWaitingContainer, { direction: 'vertical', showWaitPanel: showCicoWaitPanel, showWaitPanelPrimary: showCicoPrimaryProgress, waitPanelTitle: cicoWaitPanelTitle, waitPanelTextPrimary: cicoPrimaryProgressText, waitPanelValuePrimary: cicoPrimaryProgressValue, waitPanelMaxValuePrimary: cicoPrimaryProgressMax, isCancelable: true, abortController: abortControllerLocal, children: (groupId && groupId.length > 0) ? panelManagerContent
|
|
989
|
+
// Senza le prop di persistenza il provider si comporta come quello base:
|
|
990
|
+
// i contesti che non ricordano il layout restano come prima
|
|
991
|
+
: _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
992
|
};
|
|
860
993
|
export default TMSearchResult;
|
|
861
|
-
|
|
994
|
+
/** Cerca una voce di operazione per id, anche dentro i sottomenu */
|
|
995
|
+
const findOperationItemById = (items, id) => {
|
|
996
|
+
for (const item of items) {
|
|
997
|
+
if (item.id === id)
|
|
998
|
+
return item;
|
|
999
|
+
const found = item.submenu ? findOperationItemById(item.submenu, id) : undefined;
|
|
1000
|
+
if (found)
|
|
1001
|
+
return found;
|
|
1002
|
+
}
|
|
1003
|
+
return undefined;
|
|
1004
|
+
};
|
|
1005
|
+
/**
|
|
1006
|
+
* Azioni della colonna di riga. Gli id sono quelli di useDocumentOperations, così il comportamento è
|
|
1007
|
+
* lo stesso del menu contestuale; icone e colori sono allineati alle altre griglie mentre il tooltip
|
|
1008
|
+
* resta il nome dell'operazione. "Cancella" è la cancellazione logica: ripristino ed eliminazione
|
|
1009
|
+
* fisica restano nel menu contestuale, dove la scelta è esplicita.
|
|
1010
|
+
*/
|
|
1011
|
+
const rowActions = [
|
|
1012
|
+
{ operationId: 'open-form', icon: _jsx(IconEdit, { fontSize: 18, color: TMColors.primary }) },
|
|
1013
|
+
{ operationId: 'dup', icon: _jsx(IconDuplicate, { fontSize: 18, color: TMColors.tertiary }) },
|
|
1014
|
+
{ operationId: 'del-log', icon: _jsx(IconDelete, { fontSize: 18, color: TMColors.error }), isVisible: (rowData) => rowData?.ISLOGDEL != 1 },
|
|
1015
|
+
];
|
|
1016
|
+
const rowActionsStyles = {
|
|
1017
|
+
cell: { display: 'flex', alignItems: 'center', justifyContent: 'center', gap: '14px' },
|
|
1018
|
+
icon: { cursor: 'pointer', display: 'flex' },
|
|
1019
|
+
};
|
|
1020
|
+
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
1021
|
const [dataSource, setDataSource] = useState();
|
|
863
1022
|
const [columns, setColumns] = useState([]);
|
|
864
1023
|
const [selectedRowKeys, setSelectedRowKeys] = useState([]);
|
|
@@ -879,8 +1038,8 @@ const TMSearchResultGrid = ({ openInOffice, fromDTD, operationItems, allUsers, i
|
|
|
879
1038
|
useEffect(() => {
|
|
880
1039
|
updateDataSourceFromDataGrid(dataSource ?? []);
|
|
881
1040
|
}, [dataSource]);
|
|
882
|
-
const { loadDataListsAsync, renderDataListCell, dataListsCache } = useDataListItem();
|
|
883
|
-
const { loadUsersAsync, renderUserIdViewer, usersCache } = useDataUserIdItem();
|
|
1041
|
+
const { loadDataListsAsync, renderDataListCell, dataListsCache, getDataListItem } = useDataListItem();
|
|
1042
|
+
const { loadUsersAsync, renderUserIdViewer, usersCache, getUserItem, getCompleteUserName } = useDataUserIdItem();
|
|
884
1043
|
useEffect(() => {
|
|
885
1044
|
// Sincronizza focusedItem con inputFocusedItem dal padre
|
|
886
1045
|
if (deepCompare(inputFocusedItem, focusedItem))
|
|
@@ -1112,6 +1271,57 @@ const TMSearchResultGrid = ({ openInOffice, fromDTD, operationItems, allUsers, i
|
|
|
1112
1271
|
});
|
|
1113
1272
|
return cols;
|
|
1114
1273
|
}, [searchResult, dataType, cellRender, getDisplayFormat, dataListsCache, usersCache]);
|
|
1274
|
+
/**
|
|
1275
|
+
* Colonne in cui il testo mostrato è diverso dal valore archiviato: date e numeri formattati, descrizioni
|
|
1276
|
+
* di liste dati e utenti. Su queste la ricerca della griglia va fatta sul testo mostrato, altrimenti non
|
|
1277
|
+
* trova nulla (es. cercando 29/01/2023 su una data, che nei dati è una stringa ISO).
|
|
1278
|
+
* Le cache sono ref lette al momento della ricerca: a quel punto sono già popolate.
|
|
1279
|
+
*/
|
|
1280
|
+
const searchTextGetters = useMemo(() => {
|
|
1281
|
+
const getters = new Map();
|
|
1282
|
+
const columnsOfResult = searchResult?.dtdResult?.columns;
|
|
1283
|
+
if (!columnsOfResult)
|
|
1284
|
+
return getters;
|
|
1285
|
+
const uniqueKeys = generateUniqueColumnKeys(columnsOfResult, searchResult?.fromTID);
|
|
1286
|
+
columnsOfResult.forEach((col, index) => {
|
|
1287
|
+
const dataField = uniqueKeys[index];
|
|
1288
|
+
if (!dataField)
|
|
1289
|
+
return;
|
|
1290
|
+
const dataDomain = MetadataDataDomains[(col.extendedProperties?.["DataDomain"] ?? "None")];
|
|
1291
|
+
const dataListID = Number(col.extendedProperties?.["DataListID"]);
|
|
1292
|
+
if (dataDomain === MetadataDataDomains.DataList && dataListID) {
|
|
1293
|
+
getters.set(dataField, (rowData) => getDataListItem(dataListID, rowData?.[dataField])?.name ?? String(rowData?.[dataField] ?? ''));
|
|
1294
|
+
return;
|
|
1295
|
+
}
|
|
1296
|
+
if (dataDomain === MetadataDataDomains.UserID) {
|
|
1297
|
+
getters.set(dataField, (rowData) => {
|
|
1298
|
+
const rawValue = rowData?.[dataField];
|
|
1299
|
+
// Un campo utente vuoto non mostra nulla: senza questo controllo Number('') darebbe 0, cioè l'utente di sistema
|
|
1300
|
+
if (rawValue === undefined || rawValue === null || rawValue === '')
|
|
1301
|
+
return '';
|
|
1302
|
+
const userId = Number(rawValue);
|
|
1303
|
+
if (Number.isNaN(userId))
|
|
1304
|
+
return String(rawValue);
|
|
1305
|
+
if (userId === 0)
|
|
1306
|
+
return SDKUI_Localizator.SystemUser ?? '';
|
|
1307
|
+
const ud = getUserItem(userId);
|
|
1308
|
+
return (ud ? getCompleteUserName(ud.domain, ud.name) : undefined) ?? String(rawValue);
|
|
1309
|
+
});
|
|
1310
|
+
return;
|
|
1311
|
+
}
|
|
1312
|
+
// Data e numero vengono mostrati con il formato definito sulle proprietà estese della colonna
|
|
1313
|
+
const { format, formatCulture } = getColumnFormatInfo(col);
|
|
1314
|
+
if (col.dataType === DataColumnTypes.DateTime) {
|
|
1315
|
+
getters.set(dataField, (rowData) => getDateDisplayText(rowData?.[dataField], format, formatCulture));
|
|
1316
|
+
return;
|
|
1317
|
+
}
|
|
1318
|
+
if (col.dataType === DataColumnTypes.Number) {
|
|
1319
|
+
getters.set(dataField, (rowData) => getNumberDisplayText(rowData?.[dataField], format, formatCulture));
|
|
1320
|
+
}
|
|
1321
|
+
});
|
|
1322
|
+
return getters;
|
|
1323
|
+
}, [searchResult, getDataListItem, getUserItem, getCompleteUserName]);
|
|
1324
|
+
const customizeColumns = useMemo(() => customizeSearchByDisplayText(searchTextGetters), [searchTextGetters]);
|
|
1115
1325
|
/**
|
|
1116
1326
|
* Effect che carica i dati necessari e genera le colonne della griglia.
|
|
1117
1327
|
* Esegue il caricamento delle cache (DataList e UserID) in parallelo prima di generare le colonne,
|
|
@@ -1203,6 +1413,9 @@ const TMSearchResultGrid = ({ openInOffice, fromDTD, operationItems, allUsers, i
|
|
|
1203
1413
|
// Era sull'icona, non fare nulla
|
|
1204
1414
|
return;
|
|
1205
1415
|
}
|
|
1416
|
+
// Due click rapidi su un'icona della colonna azioni non devono aprire anche il form
|
|
1417
|
+
if (e.event?.target.closest('.tm-row-actions'))
|
|
1418
|
+
return;
|
|
1206
1419
|
// Verifica che il documento abbia TID e DID validi prima di procedere
|
|
1207
1420
|
if (!e.data.TID || !e.data.DID) {
|
|
1208
1421
|
ShowAlert({
|
|
@@ -1216,8 +1429,43 @@ const TMSearchResultGrid = ({ openInOffice, fromDTD, operationItems, allUsers, i
|
|
|
1216
1429
|
onFocusedItemChanged?.(e.data);
|
|
1217
1430
|
onDblClick();
|
|
1218
1431
|
}, [onDblClick]);
|
|
1432
|
+
/**
|
|
1433
|
+
* Colonna delle azioni di riga, in testa alla griglia (subito dopo la checkbox di selezione, che
|
|
1434
|
+
* DevExtreme tiene sempre per prima). Vive solo qui e non nello stato `columns`, che è quello
|
|
1435
|
+
* sincronizzato col padre per l'esportazione: una colonna senza dataField finirebbe in Excel come
|
|
1436
|
+
* colonna vuota.
|
|
1437
|
+
*
|
|
1438
|
+
* Le operazioni sono lette da una ref perché `operationItems` è ricostruito a ogni render del
|
|
1439
|
+
* padre: usarlo come dipendenza renderebbe nuova la colonna, e con essa `dataColumns`, ad ogni
|
|
1440
|
+
* giro. La cellRender le rilegge a ogni ridisegno della griglia, quindi resta comunque aggiornata.
|
|
1441
|
+
*/
|
|
1442
|
+
const operationItemsRef = useRef(operationItems);
|
|
1443
|
+
operationItemsRef.current = operationItems;
|
|
1444
|
+
const actionsColumn = useMemo(() => ({
|
|
1445
|
+
caption: '',
|
|
1446
|
+
width: 110,
|
|
1447
|
+
alignment: 'center',
|
|
1448
|
+
allowSorting: false,
|
|
1449
|
+
allowFiltering: false,
|
|
1450
|
+
allowHeaderFiltering: false,
|
|
1451
|
+
allowResizing: false,
|
|
1452
|
+
allowReordering: false,
|
|
1453
|
+
allowHiding: false,
|
|
1454
|
+
allowExporting: false,
|
|
1455
|
+
showInColumnChooser: false,
|
|
1456
|
+
cssClass: 'tm-row-actions',
|
|
1457
|
+
cellRender: (cellData) => (_jsx("div", { style: rowActionsStyles.cell, children: rowActions.map(action => {
|
|
1458
|
+
const operation = findOperationItemById(operationItemsRef.current, action.operationId);
|
|
1459
|
+
if (!operation || operation.visible === false)
|
|
1460
|
+
return null;
|
|
1461
|
+
if (action.isVisible && !action.isVisible(cellData.data))
|
|
1462
|
+
return null;
|
|
1463
|
+
return (_jsx("span", { style: rowActionsStyles.icon, title: operation.name, onClick: () => onRowActionRequest?.(action.operationId, cellData.data), children: action.icon }, action.operationId));
|
|
1464
|
+
}) })),
|
|
1465
|
+
}), [onRowActionRequest]);
|
|
1219
1466
|
const dataColumns = useMemo(() => {
|
|
1220
1467
|
return [
|
|
1468
|
+
...(showActionsColumn ? [actionsColumn] : []),
|
|
1221
1469
|
{
|
|
1222
1470
|
dataType: "object",
|
|
1223
1471
|
dataField: 'FILEEXT',
|
|
@@ -1231,7 +1479,7 @@ const TMSearchResultGrid = ({ openInOffice, fromDTD, operationItems, allUsers, i
|
|
|
1231
1479
|
},
|
|
1232
1480
|
...columns.filter(col => col.dataField !== 'FILEEXT')
|
|
1233
1481
|
];
|
|
1234
|
-
}, [columns, onDownloadDcmtsAsync, openInOffice]);
|
|
1482
|
+
}, [columns, onDownloadDcmtsAsync, openInOffice, showActionsColumn, actionsColumn]);
|
|
1235
1483
|
const onContentReady = useCallback((e) => {
|
|
1236
1484
|
if (e === undefined)
|
|
1237
1485
|
return;
|
|
@@ -1242,26 +1490,29 @@ const TMSearchResultGrid = ({ openInOffice, fromDTD, operationItems, allUsers, i
|
|
|
1242
1490
|
setVisibleItems(visibleData);
|
|
1243
1491
|
}, []);
|
|
1244
1492
|
useEffect(() => { onVisibleItemChanged?.(visibleItems); }, [visibleItems]);
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1493
|
+
const gridCounterConfig = useMemo(() => {
|
|
1494
|
+
if (!showCounterConfig)
|
|
1495
|
+
return { show: false };
|
|
1496
|
+
const defaultItems = dcmtsReturned !== undefined && dcmtsFound !== undefined
|
|
1497
|
+
? new Map([
|
|
1498
|
+
[CounterItemKey.allItems, {
|
|
1499
|
+
key: CounterItemKey.allItems,
|
|
1500
|
+
show: true,
|
|
1501
|
+
caption: `${dcmtsReturned} restituiti su ${dcmtsFound} trovati`,
|
|
1502
|
+
value: `${dcmtsReturned}/${dcmtsFound}`,
|
|
1503
|
+
icon: _jsx(IconAll, {}),
|
|
1504
|
+
order: -1
|
|
1505
|
+
}]
|
|
1506
|
+
])
|
|
1507
|
+
: undefined;
|
|
1508
|
+
return { ...counterConfig, show: true, items: counterConfig?.items ?? defaultItems };
|
|
1509
|
+
}, [showCounterConfig, counterConfig, dcmtsReturned, dcmtsFound]);
|
|
1510
|
+
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: { mode: "multiple" }, selection: { mode: allowMultipleSelection ? 'multiple' : 'single' }, pageSize: pageSize, compactPager: compactPager, onSelectionChanged: handleSelectionChange, onFocusedRowChanged: handleFocusedRowChange, onRowDblClick: onRowDblClick, onContentReady: onContentReady, showHeaderColumnChooser: true, onKeyDown: onKeyDown, customContextMenuItems: operationItems, counterConfig: gridCounterConfig })] });
|
|
1260
1511
|
};
|
|
1261
1512
|
//#region TMSearchResultSelector
|
|
1262
|
-
const StyledItemTemplate = styled.div `
|
|
1263
|
-
background: ${(props) => props.$isSelected ? 'oklch(from var(--dx-color-primary) l c h / .2) !important' : 'transparent'};
|
|
1264
|
-
cursor: pointer;
|
|
1513
|
+
const StyledItemTemplate = styled.div `
|
|
1514
|
+
background: ${(props) => props.$isSelected ? 'oklch(from var(--dx-color-primary) l c h / .2) !important' : 'transparent'};
|
|
1515
|
+
cursor: pointer;
|
|
1265
1516
|
`;
|
|
1266
1517
|
const MemoizedStyledItemTemplate = React.memo(StyledItemTemplate);
|
|
1267
1518
|
const TMSearchResultSelector = ({ searchResults = [], disableAccordionIfSingleCategory = false, selectedTID, selectedSearchResult, autoSelectFirst = true, onSelectionChanged }) => {
|
|
@@ -1317,14 +1568,29 @@ const TMSearchResultSelector = ({ searchResults = [], disableAccordionIfSingleCa
|
|
|
1317
1568
|
}
|
|
1318
1569
|
}
|
|
1319
1570
|
}, [sortedCategories.length, autoSelectFirst]);
|
|
1571
|
+
// La preselezione esterna va applicata una volta per valore: riapplicarla a ogni cambio di
|
|
1572
|
+
// searchResults faceva sì che un refresh annullasse la navigazione dell'utente.
|
|
1573
|
+
const appliedSelectedTIDRef = useRef(undefined);
|
|
1320
1574
|
useEffect(() => {
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1575
|
+
// Richiesta ritirata: dimentichiamo il valore applicato, così se il chiamante richiede di
|
|
1576
|
+
// nuovo lo stesso TID la preselezione riparte
|
|
1577
|
+
if (selectedTID === undefined) {
|
|
1578
|
+
appliedSelectedTIDRef.current = undefined;
|
|
1579
|
+
return;
|
|
1324
1580
|
}
|
|
1581
|
+
if (appliedSelectedTIDRef.current === selectedTID)
|
|
1582
|
+
return;
|
|
1583
|
+
const found = searchResults.find(r => Number(r.fromTID) === selectedTID);
|
|
1584
|
+
if (!found)
|
|
1585
|
+
return; // risultati non ancora arrivati: riproviamo al prossimo giro
|
|
1586
|
+
appliedSelectedTIDRef.current = selectedTID;
|
|
1587
|
+
handleSelect(found);
|
|
1325
1588
|
}, [selectedTID, searchResults]);
|
|
1326
|
-
|
|
1327
|
-
|
|
1589
|
+
// force = true per i click dell'utente: la selezione va notificata anche se il tipo documento è già quello selezionato
|
|
1590
|
+
const handleSelect = useCallback((result, force = false) => {
|
|
1591
|
+
if (result === undefined)
|
|
1592
|
+
return;
|
|
1593
|
+
if (selectedResult !== result || force) {
|
|
1328
1594
|
setSelectedResult(result);
|
|
1329
1595
|
onSelectionChanged?.(result);
|
|
1330
1596
|
}
|
|
@@ -1369,113 +1635,169 @@ const TMSearchResultSelector = ({ searchResults = [], disableAccordionIfSingleCa
|
|
|
1369
1635
|
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 })] })),
|
|
1370
1636
|
itemHeight: 40
|
|
1371
1637
|
})), [sortedCategories, groupedResults, searchResults]);
|
|
1372
|
-
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), children: renderItemTemplate(result) }, index))) }));
|
|
1638
|
+
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))) }));
|
|
1373
1639
|
if (disableAccordionIfSingleCategory && sortedCategories.length === 1) {
|
|
1374
1640
|
const category = sortedCategories[0];
|
|
1375
1641
|
return renderCategoryItems(category);
|
|
1376
1642
|
}
|
|
1377
|
-
return (_jsx(TMAccordionNew, { groups: accordionGroups, selectedItem: selectedResult, onSelectedItemChange: (result) => handleSelect(result) }));
|
|
1643
|
+
return (_jsx(TMAccordionNew, { groups: accordionGroups, selectedItem: selectedResult, onSelectedItemChange: (result) => handleSelect(result, true) }));
|
|
1378
1644
|
};
|
|
1379
1645
|
//#endregion TMSearchResultSelector
|
|
1380
|
-
|
|
1381
|
-
|
|
1646
|
+
/** Senza UI: vive dentro il provider e passa a onBack, via ref, l'azione "mostra il pannello lista". */
|
|
1647
|
+
const ShowMainPanelBridge = ({ showMainPanelRef }) => {
|
|
1648
|
+
const { setPanelVisibilityById } = useTMPanelManagerContext();
|
|
1382
1649
|
useEffect(() => {
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1650
|
+
// Su mobile mostrare un pannello nasconde gli altri; su desktop la lista è già visibile
|
|
1651
|
+
showMainPanelRef.current = () => setPanelVisibilityById('tmSearchResult', true);
|
|
1652
|
+
return () => { showMainPanelRef.current = null; };
|
|
1653
|
+
}, [setPanelVisibilityById, showMainPanelRef]);
|
|
1654
|
+
return null;
|
|
1655
|
+
};
|
|
1656
|
+
/** Senza UI: allinea i pannelli quando il layout viene salvato da un altro risultato di ricerca già aperto */
|
|
1657
|
+
const SavedLayoutSyncHandler = ({ disabledPanelIds }) => {
|
|
1658
|
+
const { panelVisibility, panelDimensions, maximizedPanels, isResizingActive, setPanelVisibilityById, setPanelDimensionsById } = useTMPanelManagerContext();
|
|
1659
|
+
// Il layout è condiviso fra i risultati aperti: si sottoscrive la firma, che è una stringa, perché
|
|
1660
|
+
// React confronta le letture per riferimento e su un oggetto ri-renderizzerebbe all'infinito
|
|
1661
|
+
const savedLayoutSignature = useSyncExternalStore(subscribeSearchResultPanelLayout, getSearchResultPanelLayoutSignature);
|
|
1662
|
+
useEffect(() => {
|
|
1663
|
+
// Con un pannello massimizzato o un separatore in movimento comanda l'utente di questa istanza
|
|
1664
|
+
if (maximizedPanels.length > 0 || isResizingActive)
|
|
1665
|
+
return;
|
|
1666
|
+
// Al mount panelVisibility è ancora vuota: lo stato iniziale lo applica il provider.
|
|
1667
|
+
// Un pannello disabilitato qui non va aperto, gli altri si allineano comunque
|
|
1668
|
+
const panelsToApply = Object.entries(getSearchResultPanelLayout())
|
|
1669
|
+
.filter(([id, state]) => panelVisibility[id] !== undefined && !(state?.visible && disabledPanelIds.includes(id)));
|
|
1670
|
+
panelsToApply.forEach(([id, state]) => {
|
|
1671
|
+
const isVisible = state?.visible ?? false;
|
|
1672
|
+
if (panelVisibility[id] !== isVisible)
|
|
1673
|
+
setPanelVisibilityById(id, isVisible);
|
|
1674
|
+
});
|
|
1675
|
+
// Le larghezze salvate valgono come pesi, non come percentuali: qui si normalizzano sui soli pannelli
|
|
1676
|
+
// che questo risultato apre davvero, così lo spazio di quelli scartati non resta vuoto
|
|
1677
|
+
const panelsToShow = panelsToApply.filter(([, state]) => state?.visible && parseFloat(state.width) > 0 && parseFloat(state.height) > 0);
|
|
1678
|
+
const weightTotal = panelsToShow.reduce((total, [, state]) => total + parseFloat(state.width), 0);
|
|
1679
|
+
if (weightTotal <= 0)
|
|
1680
|
+
return;
|
|
1681
|
+
// Dopo la visibilità, che accoda un suo ricalcolo delle quote: così restano quelle salvate.
|
|
1682
|
+
// Le quote sono arrotondate, altrimenti due risultati si rincorrono sugli ultimi decimali
|
|
1683
|
+
panelsToShow.forEach(([id, state]) => {
|
|
1684
|
+
const width = `${Math.round(parseFloat(state.width) / weightTotal * 10000) / 100}%`;
|
|
1685
|
+
if (panelDimensions[id]?.width === width && panelDimensions[id]?.height === state.height)
|
|
1686
|
+
return;
|
|
1687
|
+
setPanelDimensionsById(id, width, state.height);
|
|
1688
|
+
});
|
|
1689
|
+
}, [savedLayoutSignature]);
|
|
1690
|
+
return null;
|
|
1691
|
+
};
|
|
1692
|
+
const PanelDisabledStateHandler = ({ isBoardDisabled, savedBlogVisible = false }) => {
|
|
1693
|
+
const { panelVisibility, setPanelVisibilityById, setToolbarButtonDisabled } = useTMPanelManagerContext();
|
|
1694
|
+
const isBlogVisible = panelVisibility['tmBlog'] ?? false;
|
|
1695
|
+
useEffect(() => {
|
|
1696
|
+
setToolbarButtonDisabled('tmBlog', isBoardDisabled);
|
|
1390
1697
|
}, [isBoardDisabled]);
|
|
1698
|
+
/**
|
|
1699
|
+
* Senza bacheca nel tipo documento il pannello va chiuso ogni volta che ricompare, non solo al cambio
|
|
1700
|
+
* di stato: il layout salvato viene applicato dopo questo effetto e può riportarlo a video.
|
|
1701
|
+
* È un effetto di layout per chiuderlo prima che venga disegnato, altrimenti lampeggia.
|
|
1702
|
+
*/
|
|
1703
|
+
useLayoutEffect(() => {
|
|
1704
|
+
if (isBoardDisabled && isBlogVisible)
|
|
1705
|
+
setPanelVisibilityById('tmBlog', false);
|
|
1706
|
+
}, [isBoardDisabled, isBlogVisible]);
|
|
1707
|
+
// Bacheca di nuovo prevista: si riapre come da layout salvato. isBlogVisible non è fra le dipendenze,
|
|
1708
|
+
// altrimenti riaprirebbe il pannello appena chiuso dall'utente
|
|
1709
|
+
useEffect(() => {
|
|
1710
|
+
if (!isBoardDisabled && savedBlogVisible && !isBlogVisible)
|
|
1711
|
+
setPanelVisibilityById('tmBlog', true);
|
|
1712
|
+
}, [isBoardDisabled, savedBlogVisible]);
|
|
1391
1713
|
return null;
|
|
1392
1714
|
};
|
|
1393
|
-
const TMDcmtPreviewWrapper = ({ refreshPreviewTrigger, currentDcmt, isVisible, onBack }) => {
|
|
1715
|
+
const TMDcmtPreviewWrapper = ({ refreshPreviewTrigger, currentDcmt, isVisible, isPageVisible = true, onBack }) => {
|
|
1394
1716
|
const { setPanelVisibilityById, toggleMaximize, isResizingActive, countVisibleLeafPanels } = useTMPanelManagerContext();
|
|
1395
1717
|
const deviceType = useDeviceType();
|
|
1396
1718
|
const isMobile = deviceType === DeviceType.MOBILE;
|
|
1397
|
-
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));
|
|
1719
|
+
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));
|
|
1398
1720
|
};
|
|
1399
1721
|
// Styled Components
|
|
1400
|
-
const StyledPlaceholder = styled.div `
|
|
1401
|
-
padding: 20px;
|
|
1402
|
-
text-align: center;
|
|
1403
|
-
color: #888;
|
|
1722
|
+
const StyledPlaceholder = styled.div `
|
|
1723
|
+
padding: 20px;
|
|
1724
|
+
text-align: center;
|
|
1725
|
+
color: #888;
|
|
1404
1726
|
`;
|
|
1405
|
-
const StyledIndexingInfoSection = styled.div `
|
|
1406
|
-
padding: 15px;
|
|
1407
|
-
border-top: 1px solid #e0e0e0;
|
|
1408
|
-
background: linear-gradient(to bottom, #f9f9f9, #f5f5f5);
|
|
1409
|
-
display: flex;
|
|
1410
|
-
flex-direction: column;
|
|
1411
|
-
gap: 10px;
|
|
1727
|
+
const StyledIndexingInfoSection = styled.div `
|
|
1728
|
+
padding: 15px;
|
|
1729
|
+
border-top: 1px solid #e0e0e0;
|
|
1730
|
+
background: linear-gradient(to bottom, #f9f9f9, #f5f5f5);
|
|
1731
|
+
display: flex;
|
|
1732
|
+
flex-direction: column;
|
|
1733
|
+
gap: 10px;
|
|
1412
1734
|
`;
|
|
1413
|
-
const StyledIndexingToggle = styled.button `
|
|
1414
|
-
display: flex;
|
|
1415
|
-
align-items: center;
|
|
1416
|
-
justify-content: space-between;
|
|
1417
|
-
width: 100%;
|
|
1418
|
-
padding: 10px 16px;
|
|
1419
|
-
background: white;
|
|
1420
|
-
border: 1px solid #d0d0d0;
|
|
1421
|
-
border-radius: 6px;
|
|
1422
|
-
cursor: ${props => props.disabled ? 'not-allowed' : 'pointer'};
|
|
1423
|
-
transition: all 0.2s ease;
|
|
1424
|
-
font-size: 14px;
|
|
1425
|
-
font-weight: 500;
|
|
1426
|
-
color: #333;
|
|
1427
|
-
opacity: ${props => props.disabled ? 0.6 : 1};
|
|
1428
|
-
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
|
|
1429
|
-
|
|
1430
|
-
&:hover:not(:disabled) {
|
|
1431
|
-
background: #f8f8f8;
|
|
1432
|
-
border-color: #2196F3;
|
|
1433
|
-
box-shadow: 0 2px 4px rgba(33, 150, 243, 0.2);
|
|
1434
|
-
}
|
|
1435
|
-
|
|
1436
|
-
&:active:not(:disabled) {
|
|
1437
|
-
transform: translateY(1px);
|
|
1438
|
-
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
|
1439
|
-
}
|
|
1735
|
+
const StyledIndexingToggle = styled.button `
|
|
1736
|
+
display: flex;
|
|
1737
|
+
align-items: center;
|
|
1738
|
+
justify-content: space-between;
|
|
1739
|
+
width: 100%;
|
|
1740
|
+
padding: 10px 16px;
|
|
1741
|
+
background: white;
|
|
1742
|
+
border: 1px solid #d0d0d0;
|
|
1743
|
+
border-radius: 6px;
|
|
1744
|
+
cursor: ${props => props.disabled ? 'not-allowed' : 'pointer'};
|
|
1745
|
+
transition: all 0.2s ease;
|
|
1746
|
+
font-size: 14px;
|
|
1747
|
+
font-weight: 500;
|
|
1748
|
+
color: #333;
|
|
1749
|
+
opacity: ${props => props.disabled ? 0.6 : 1};
|
|
1750
|
+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
|
|
1751
|
+
|
|
1752
|
+
&:hover:not(:disabled) {
|
|
1753
|
+
background: #f8f8f8;
|
|
1754
|
+
border-color: #2196F3;
|
|
1755
|
+
box-shadow: 0 2px 4px rgba(33, 150, 243, 0.2);
|
|
1756
|
+
}
|
|
1757
|
+
|
|
1758
|
+
&:active:not(:disabled) {
|
|
1759
|
+
transform: translateY(1px);
|
|
1760
|
+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
|
1761
|
+
}
|
|
1440
1762
|
`;
|
|
1441
|
-
const StyledLeftContent = styled.div `
|
|
1442
|
-
display: flex;
|
|
1443
|
-
align-items: center;
|
|
1444
|
-
gap: 8px;
|
|
1763
|
+
const StyledLeftContent = styled.div `
|
|
1764
|
+
display: flex;
|
|
1765
|
+
align-items: center;
|
|
1766
|
+
gap: 8px;
|
|
1445
1767
|
`;
|
|
1446
|
-
const StyledRightContent = styled.div `
|
|
1447
|
-
display: flex;
|
|
1448
|
-
align-items: center;
|
|
1449
|
-
gap: 8px;
|
|
1768
|
+
const StyledRightContent = styled.div `
|
|
1769
|
+
display: flex;
|
|
1770
|
+
align-items: center;
|
|
1771
|
+
gap: 8px;
|
|
1450
1772
|
`;
|
|
1451
|
-
const StyledChevron = styled.span `
|
|
1452
|
-
transition: transform 0.2s ease;
|
|
1453
|
-
transform: ${props => props.$isOpen ? 'rotate(180deg)' : 'rotate(0deg)'};
|
|
1454
|
-
color: #666;
|
|
1455
|
-
font-size: 12px;
|
|
1773
|
+
const StyledChevron = styled.span `
|
|
1774
|
+
transition: transform 0.2s ease;
|
|
1775
|
+
transform: ${props => props.$isOpen ? 'rotate(180deg)' : 'rotate(0deg)'};
|
|
1776
|
+
color: #666;
|
|
1777
|
+
font-size: 12px;
|
|
1456
1778
|
`;
|
|
1457
|
-
const StyledIndexingInfoBox = styled.div `
|
|
1458
|
-
position: relative;
|
|
1459
|
-
background: white;
|
|
1460
|
-
border: 1px solid #e0e0e0;
|
|
1461
|
-
border-radius: 6px;
|
|
1462
|
-
padding: 12px;
|
|
1463
|
-
max-height: 200px;
|
|
1464
|
-
overflow: auto;
|
|
1465
|
-
font-family: 'Courier New', monospace;
|
|
1466
|
-
font-size: 12px;
|
|
1467
|
-
color: #333;
|
|
1468
|
-
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
1469
|
-
animation: slideDown 0.2s ease;
|
|
1470
|
-
|
|
1471
|
-
@keyframes slideDown {
|
|
1472
|
-
from {
|
|
1473
|
-
opacity: 0;
|
|
1474
|
-
transform: translateY(-10px);
|
|
1475
|
-
}
|
|
1476
|
-
to {
|
|
1477
|
-
opacity: 1;
|
|
1478
|
-
transform: translateY(0);
|
|
1479
|
-
}
|
|
1480
|
-
}
|
|
1779
|
+
const StyledIndexingInfoBox = styled.div `
|
|
1780
|
+
position: relative;
|
|
1781
|
+
background: white;
|
|
1782
|
+
border: 1px solid #e0e0e0;
|
|
1783
|
+
border-radius: 6px;
|
|
1784
|
+
padding: 12px;
|
|
1785
|
+
max-height: 200px;
|
|
1786
|
+
overflow: auto;
|
|
1787
|
+
font-family: 'Courier New', monospace;
|
|
1788
|
+
font-size: 12px;
|
|
1789
|
+
color: #333;
|
|
1790
|
+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
1791
|
+
animation: slideDown 0.2s ease;
|
|
1792
|
+
|
|
1793
|
+
@keyframes slideDown {
|
|
1794
|
+
from {
|
|
1795
|
+
opacity: 0;
|
|
1796
|
+
transform: translateY(-10px);
|
|
1797
|
+
}
|
|
1798
|
+
to {
|
|
1799
|
+
opacity: 1;
|
|
1800
|
+
transform: translateY(0);
|
|
1801
|
+
}
|
|
1802
|
+
}
|
|
1481
1803
|
`;
|