@topconsultnpm/sdkui-react 6.22.0-dev2.9 → 6.22.0-t2
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/ContextMenu/styles.d.ts +45 -43
- package/lib/components/NewComponents/FloatingMenuBar/TMFloatingMenuBar.js +1 -1
- package/lib/components/NewComponents/FloatingMenuBar/styles.d.ts +67 -60
- package/lib/components/base/Styled.d.ts +93 -77
- package/lib/components/base/TMCounterBar.d.ts +2 -2
- package/lib/components/base/TMCounterContainer.d.ts +2 -1
- package/lib/components/base/TMCustomButton.d.ts +1 -1
- package/lib/components/base/TMDataGrid.d.ts +2 -0
- package/lib/components/base/TMDataGrid.js +260 -8
- package/lib/components/base/TMDataGridExportForm.d.ts +2 -1
- package/lib/components/base/TMEditorBase.d.ts +2 -0
- package/lib/components/base/TMFileManager.d.ts +2 -1
- package/lib/components/base/TMFileManager.js +5 -3
- package/lib/components/base/TMFileManagerDataGridView.d.ts +2 -1
- package/lib/components/base/TMFileManagerDataGridView.js +11 -2
- package/lib/components/base/TMFileManagerThumbnailItems.d.ts +1 -1
- package/lib/components/base/TMFileManagerThumbnailItems.js +19 -9
- package/lib/components/base/TMFileManagerThumbnailsView.d.ts +1 -1
- package/lib/components/base/TMFileManagerUtils.d.ts +6 -6
- package/lib/components/base/TMFileManagerUtils.js +37 -1
- package/lib/components/base/TMLayout.d.ts +4 -4
- package/lib/components/base/TMList.d.ts +2 -1
- package/lib/components/base/TMListView.d.ts +1 -1
- package/lib/components/base/TMModal.d.ts +11 -0
- package/lib/components/base/TMModal.js +47 -13
- package/lib/components/base/TMPanel.d.ts +6 -0
- package/lib/components/base/TMPanel.js +138 -25
- package/lib/components/base/TMPopUp.js +3 -0
- package/lib/components/base/TMSpinner.d.ts +2 -1
- package/lib/components/base/TMTab.d.ts +4 -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 +14 -8
- package/lib/components/base/TMTreeView.js +108 -67
- package/lib/components/base/TMUserAvatar.d.ts +2 -1
- package/lib/components/base/TMVilViewer.d.ts +2 -1
- package/lib/components/base/TMWaitPanel.d.ts +3 -2
- 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/TMDynDataListItemChooser.d.ts +1 -1
- package/lib/components/choosers/TMInvoiceRetrieveFormats.d.ts +2 -1
- package/lib/components/choosers/TMMetadataChooser.js +1 -1
- package/lib/components/choosers/TMOrderRetrieveFormats.d.ts +2 -1
- 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.d.ts +3 -3
- package/lib/components/choosers/TMSelectedValuesSummary.d.ts +13 -0
- package/lib/components/choosers/TMSelectedValuesSummary.js +91 -0
- package/lib/components/choosers/TMUserChooser.d.ts +2 -2
- package/lib/components/editors/TMDropDown.d.ts +3 -0
- package/lib/components/editors/TMDropDown.js +197 -5
- package/lib/components/editors/TMEditorStyled.d.ts +20 -42
- package/lib/components/editors/TMFormulaEditor.d.ts +1 -1
- package/lib/components/editors/TMHtmlContentDisplay.d.ts +2 -1
- package/lib/components/editors/TMHtmlEditor.d.ts +2 -1
- package/lib/components/editors/TMTreeDropDown.d.ts +1 -1
- package/lib/components/features/archive/TMArchive.js +17 -3
- package/lib/components/features/assistant/TMToppyDraggableHelpCenter.d.ts +1 -1
- package/lib/components/features/blog/TMBlogCommentForm.d.ts +2 -1
- 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 +178 -51
- package/lib/components/features/documents/TMDcmtFormActionButtons.d.ts +12 -1
- package/lib/components/features/documents/TMDcmtFormActionButtons.js +77 -7
- package/lib/components/features/documents/TMDcmtIcon.d.ts +2 -1
- package/lib/components/features/documents/TMDcmtIcon.js +5 -3
- package/lib/components/features/documents/TMDcmtPreview.d.ts +8 -6
- package/lib/components/features/documents/TMDcmtPreview.js +10 -6
- package/lib/components/features/documents/TMDcmtTasks.d.ts +2 -1
- package/lib/components/features/documents/TMDragDropOverlay.d.ts +1 -1
- package/lib/components/features/documents/TMMasterDetailDcmts.js +95 -33
- package/lib/components/features/documents/TMMasterInfoFields.d.ts +20 -0
- package/lib/components/features/documents/TMMasterInfoFields.js +186 -0
- package/lib/components/features/documents/TMMergeToPdfForm.d.ts +3 -3
- package/lib/components/features/documents/TMMergeToPdfForm.js +30 -5
- package/lib/components/features/documents/TMMultiMasterDetailDcmtsForm.d.ts +46 -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/TMDcmtCheckoutInfoForm.d.ts +2 -1
- package/lib/components/features/search/TMMetadataOutputForm.d.ts +2 -1
- package/lib/components/features/search/TMMetadataSorterForm.d.ts +2 -1
- package/lib/components/features/search/TMSavedQuerySelector.d.ts +2 -2
- package/lib/components/features/search/TMSearch.js +77 -11
- package/lib/components/features/search/TMSearchQueryEditor.js +5 -3
- package/lib/components/features/search/TMSearchQueryPanel.d.ts +13 -3
- package/lib/components/features/search/TMSearchQueryPanel.js +141 -67
- package/lib/components/features/search/TMSearchResult.d.ts +16 -0
- package/lib/components/features/search/TMSearchResult.js +429 -108
- package/lib/components/features/search/TMSearchResultFloatingActionButton.d.ts +1 -1
- package/lib/components/features/search/TMSignatureInfoContent.d.ts +2 -1
- package/lib/components/features/search/TMTreeSelector.js +109 -64
- package/lib/components/features/search/TMViewHistoryDcmt.d.ts +2 -1
- package/lib/components/features/tasks/TMTaskForm.d.ts +1 -1
- package/lib/components/features/tasks/TMTaskFormUtils.d.ts +10 -10
- package/lib/components/features/tasks/TMTasksAgenda.d.ts +1 -1
- package/lib/components/features/tasks/TMTasksCalendar.d.ts +1 -1
- package/lib/components/features/tasks/TMTasksHeader.d.ts +1 -1
- package/lib/components/features/tasks/TMTasksPanelContent.d.ts +1 -1
- package/lib/components/features/tasks/TMTasksUtilsView.d.ts +5 -5
- package/lib/components/features/tasks/TMTasksView.d.ts +1 -1
- package/lib/components/features/wg/TMWGsCopyMoveForm.d.ts +3 -2
- package/lib/components/features/workflow/TMWorkflowPopup.d.ts +18 -7
- package/lib/components/features/workflow/TMWorkflowPopup.js +8 -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/Chooser.d.ts +2 -2
- package/lib/components/forms/TMChooserForm.d.ts +2 -1
- package/lib/components/forms/TMSaveForm.d.ts +4 -4
- package/lib/components/grids/TMBlogAttachments.d.ts +2 -1
- package/lib/components/grids/TMBlogAttachments.js +13 -2
- package/lib/components/grids/TMBlogHeader.d.ts +1 -1
- package/lib/components/grids/TMBlogHeader.js +5 -1
- package/lib/components/grids/TMBlogsPost.d.ts +3 -1
- package/lib/components/grids/TMBlogsPost.js +31 -4
- package/lib/components/grids/TMBlogsPostUtils.d.ts +10 -9
- package/lib/components/grids/TMBlogsPostUtils.js +14 -3
- package/lib/components/grids/TMValidationItemsList.d.ts +2 -1
- package/lib/components/layout/panelManager/TMPanelManagerContainer.d.ts +3 -1
- package/lib/components/layout/panelManager/TMPanelManagerContainer.js +24 -14
- package/lib/components/layout/panelManager/TMPanelManagerContext.d.ts +2 -2
- package/lib/components/layout/panelManager/TMPanelManagerContext.js +68 -93
- package/lib/components/layout/panelManager/TMPanelManagerToolbar.d.ts +5 -6
- package/lib/components/layout/panelManager/TMPanelManagerWithPersistenceProvider.d.ts +2 -2
- package/lib/components/layout/panelManager/TMPanelWrapper.d.ts +2 -2
- 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/pages/TMPage.d.ts +1 -1
- package/lib/components/query/TMQueryEditor.d.ts +14 -10
- package/lib/components/settings/SettingsAppearance.d.ts +2 -1
- package/lib/components/sidebar/TMAboutApp.d.ts +2 -1
- package/lib/components/sidebar/TMCommandsPanel.d.ts +4 -4
- package/lib/components/sidebar/TMHeader.d.ts +3 -3
- package/lib/components/sidebar/TMHeader.js +30 -20
- package/lib/components/viewers/TMDataListItemViewer.d.ts +3 -2
- package/lib/components/viewers/TMDataUserIdItemViewer.d.ts +3 -2
- package/lib/components/viewers/TMMidViewer.d.ts +2 -2
- package/lib/components/viewers/TMMidViewer.js +4 -1
- package/lib/components/viewers/TMTidViewer.d.ts +2 -2
- package/lib/components/viewers/TMTidViewer.js +86 -25
- 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/SDKUI_Globals.d.ts +110 -0
- package/lib/helper/SDKUI_Globals.js +151 -0
- package/lib/helper/SDKUI_Localizator.d.ts +44 -0
- package/lib/helper/SDKUI_Localizator.js +440 -0
- package/lib/helper/TMAppUpdatedModal.d.ts +2 -0
- package/lib/helper/TMAppUpdatedModal.js +134 -0
- package/lib/helper/TMCommandsContextMenu.d.ts +1 -1
- package/lib/helper/TMIcons.d.ts +280 -279
- package/lib/helper/TMIcons.js +3 -0
- package/lib/helper/TMPdfViewer.d.ts +2 -1
- package/lib/helper/TMToppyMessage.d.ts +2 -2
- package/lib/helper/TMUtils.d.ts +23 -4
- package/lib/helper/TMUtils.js +24 -2
- 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 +12 -1
- package/lib/helper/helpers.js +25 -1
- package/lib/helper/index.d.ts +2 -0
- package/lib/helper/index.js +2 -0
- package/lib/helper/queryHelper.d.ts +6 -1
- package/lib/helper/queryHelper.js +8 -3
- package/lib/hooks/tmDistinctValuesGridHelper.d.ts +16 -0
- package/lib/hooks/tmDistinctValuesGridHelper.js +31 -0
- package/lib/hooks/useArchiveListForm.d.ts +39 -0
- package/lib/hooks/useArchiveListForm.js +46 -0
- package/lib/hooks/useCaseFlowApprove.d.ts +56 -0
- package/lib/hooks/useCaseFlowApprove.js +157 -0
- package/lib/hooks/useDataUserIdItem.d.ts +1 -0
- package/lib/hooks/useDataUserIdItem.js +1 -0
- package/lib/hooks/useDocumentOperations.d.ts +4 -0
- package/lib/hooks/useDocumentOperations.js +52 -10
- package/lib/hooks/useInputDialog.d.ts +2 -1
- package/lib/hooks/useMultiMasterDetailDcmts.d.ts +113 -0
- package/lib/hooks/useMultiMasterDetailDcmts.js +760 -0
- package/lib/hooks/useRelatedDocuments.d.ts +1 -0
- package/lib/hooks/useRelatedDocuments.js +22 -27
- package/lib/hooks/useShowDossiersV5.d.ts +12 -0
- package/lib/hooks/useShowDossiersV5.js +37 -0
- package/lib/hooks/useTMDistinctValuesMetadataDisplay.d.ts +18 -0
- package/lib/hooks/useTMDistinctValuesMetadataDisplay.js +103 -0
- package/lib/hooks/useTMDistinctValuesQuickSearch.d.ts +49 -0
- package/lib/hooks/useTMDistinctValuesQuickSearch.js +307 -0
- package/lib/hooks/useTMDistinctValuesSelection.d.ts +42 -0
- package/lib/hooks/useTMDistinctValuesSelection.js +103 -0
- package/lib/hooks/useTMDistinctValuesSource.d.ts +29 -0
- package/lib/hooks/useTMDistinctValuesSource.js +105 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.js +5 -2
- package/lib/services/caseflow/CaseFlowService.d.ts +236 -0
- package/lib/services/caseflow/CaseFlowService.js +693 -0
- package/lib/services/caseflow/CaseFlowTemplateCacheService.d.ts +28 -0
- package/lib/services/caseflow/CaseFlowTemplateCacheService.js +121 -0
- package/lib/services/caseflow/caseFlowNameCache.d.ts +32 -0
- package/lib/services/caseflow/caseFlowNameCache.js +116 -0
- package/lib/services/caseflow/caseFlowWorkItemUtils.d.ts +61 -0
- package/lib/services/caseflow/caseFlowWorkItemUtils.js +113 -0
- package/lib/services/index.d.ts +4 -0
- package/lib/services/index.js +4 -0
- package/lib/services/platform_services.d.ts +4 -3
- package/package.json +9 -5
|
@@ -67,6 +67,7 @@ export interface UseRelatedDocumentsReturn {
|
|
|
67
67
|
checkManyToManyCapability: () => Promise<void>;
|
|
68
68
|
archiveRelatedDcmtHandler: (relation: RelationDescriptor, type: 'detail' | 'master') => Promise<void>;
|
|
69
69
|
executeManyToManyPairing: (relation: RelationDescriptor, isPairing: boolean) => Promise<void>;
|
|
70
|
+
backToPairSearchModal: (() => void) | undefined;
|
|
70
71
|
}
|
|
71
72
|
export declare const useRelatedDocuments: ({ selectedSearchResult, focusedItem, currentSearchResults }: UseRelatedDocumentsProps) => UseRelatedDocumentsReturn;
|
|
72
73
|
export {};
|
|
@@ -2,7 +2,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import { useState, useCallback, useMemo, useEffect } from 'react';
|
|
3
3
|
import { SDKUI_Localizator } from '../helper/SDKUI_Localizator';
|
|
4
4
|
import { IconPair, IconUnpair } from '../helper/TMIcons';
|
|
5
|
-
import { hasDetailRelations, hasMasterRelations } from '../helper/dcmtsHelper';
|
|
5
|
+
import { hasDetailRelations, hasMasterRelations, mapRelationAssociationsToMids } from '../helper/dcmtsHelper';
|
|
6
6
|
import { SDK_Globals, SearchEngine, RelationCacheService, RelationTypes, DcmtTypeListCacheService, SystemMIDsAsNumber, AccessLevelsEx } from '@topconsultnpm/sdk-ts';
|
|
7
7
|
import { TMSpinner, TMExceptionBoxManager, ShowAlert } from '../components';
|
|
8
8
|
export const useRelatedDocuments = ({ selectedSearchResult, focusedItem, currentSearchResults }) => {
|
|
@@ -28,6 +28,7 @@ export const useRelatedDocuments = ({ selectedSearchResult, focusedItem, current
|
|
|
28
28
|
const [pairSearchModalParentDID, setPairSearchModalParentDID] = useState(undefined);
|
|
29
29
|
const [pairSearchModalRelation, setPairSearchModalRelation] = useState(undefined);
|
|
30
30
|
const [pairSearchModalInputMids, setPairSearchModalInputMids] = useState(undefined);
|
|
31
|
+
const [pairSearchContext, setPairSearchContext] = useState(undefined);
|
|
31
32
|
const [currentTIDHasDetailRelations, setCurrentTIDHasDetailRelations] = useState();
|
|
32
33
|
const [currentTIDHasMasterRelations, setCurrentTIDHasMasterRelations] = useState();
|
|
33
34
|
const [canArchiveMasterRelation, setCanArchiveMasterRelation] = useState(false);
|
|
@@ -86,6 +87,7 @@ export const useRelatedDocuments = ({ selectedSearchResult, focusedItem, current
|
|
|
86
87
|
if (!tms)
|
|
87
88
|
return;
|
|
88
89
|
const se = new SearchEngine(tms);
|
|
90
|
+
const operationTitle = isPairing ? SDKUI_Localizator.MatchManyDocumentsManyToMany : SDKUI_Localizator.UnmatchManyDocumentsManyToMany;
|
|
89
91
|
try {
|
|
90
92
|
TMSpinner.show({ description: isPairing ? 'Abbinamento in corso...' : 'Disabbinamento in corso...' });
|
|
91
93
|
for (const doc of selected) {
|
|
@@ -115,10 +117,16 @@ export const useRelatedDocuments = ({ selectedSearchResult, focusedItem, current
|
|
|
115
117
|
}
|
|
116
118
|
}
|
|
117
119
|
onCloseModal();
|
|
120
|
+
ShowAlert({
|
|
121
|
+
message: SDKUI_Localizator.OperationSuccess,
|
|
122
|
+
mode: 'success',
|
|
123
|
+
title: operationTitle,
|
|
124
|
+
duration: 3000
|
|
125
|
+
});
|
|
118
126
|
}
|
|
119
127
|
catch (error) {
|
|
120
128
|
console.error('Error in onClick:', error);
|
|
121
|
-
TMExceptionBoxManager.show({ exception: error });
|
|
129
|
+
TMExceptionBoxManager.show({ title: operationTitle, exception: error });
|
|
122
130
|
}
|
|
123
131
|
finally {
|
|
124
132
|
TMSpinner.hide();
|
|
@@ -129,6 +137,14 @@ export const useRelatedDocuments = ({ selectedSearchResult, focusedItem, current
|
|
|
129
137
|
}), []);
|
|
130
138
|
const pairFloatingActionConfig = useMemo(() => createPairFloatingActionConfig(selectedManyToManyRelation, focusedItem?.TID ? Number(focusedItem.TID) : undefined, focusedItem?.DID ? Number(focusedItem.DID) : undefined, isPairingManyToMany, () => setShowPairDcmtsModal(false)), [createPairFloatingActionConfig, selectedManyToManyRelation, focusedItem, isPairingManyToMany]);
|
|
131
139
|
const pairSearchModalFloatingActionConfig = useMemo(() => createPairFloatingActionConfig(pairSearchModalRelation, pairSearchModalParentTID, pairSearchModalParentDID, true, () => setShowPairSearchModal(false)), [createPairFloatingActionConfig, pairSearchModalRelation, pairSearchModalParentTID, pairSearchModalParentDID]);
|
|
140
|
+
const backToPairSearchModal = useMemo(() => {
|
|
141
|
+
if (!pairSearchContext)
|
|
142
|
+
return undefined;
|
|
143
|
+
return () => {
|
|
144
|
+
setShowPairDcmtsModal(false);
|
|
145
|
+
openPairSearchModal(pairSearchContext.relation, pairSearchContext.targetTID, pairSearchContext.qd);
|
|
146
|
+
};
|
|
147
|
+
}, [pairSearchContext, openPairSearchModal]);
|
|
132
148
|
const getAllRelationsAsync = async () => {
|
|
133
149
|
const tmSession = SDK_Globals.tmSession;
|
|
134
150
|
try {
|
|
@@ -224,31 +240,7 @@ export const useRelatedDocuments = ({ selectedSearchResult, focusedItem, current
|
|
|
224
240
|
};
|
|
225
241
|
//This ensures archive master/detail works correctly regardless of output metadata configuration.
|
|
226
242
|
const mapAssociationsToMidsAsync = useCallback(async (relation, type) => {
|
|
227
|
-
|
|
228
|
-
return [];
|
|
229
|
-
if (!focusedItem?.TID || !focusedItem?.DID)
|
|
230
|
-
return [];
|
|
231
|
-
const searchEngine = SDK_Globals.tmSession?.NewSearchEngine();
|
|
232
|
-
if (!searchEngine)
|
|
233
|
-
return [];
|
|
234
|
-
const allMetadata = await searchEngine.GetMetadataAsync(focusedItem.TID, focusedItem.DID, false);
|
|
235
|
-
if (!allMetadata?.dtdResult?.rows?.[0] || !allMetadata.selectMIDs)
|
|
236
|
-
return [];
|
|
237
|
-
const row = allMetadata.dtdResult.rows[0];
|
|
238
|
-
const mids = allMetadata.selectMIDs;
|
|
239
|
-
const metadataMap = new Map();
|
|
240
|
-
mids.forEach((mid, index) => {
|
|
241
|
-
const value = row[index];
|
|
242
|
-
if (value !== undefined && value !== null) {
|
|
243
|
-
metadataMap.set(mid, value.toString());
|
|
244
|
-
}
|
|
245
|
-
});
|
|
246
|
-
return relation.associations.map(assoc => {
|
|
247
|
-
const sourceMid = type === 'detail' ? (assoc.item1 ?? 0) : (assoc.item2 ?? 0);
|
|
248
|
-
const targetMid = type === 'detail' ? (assoc.item2 ?? 0) : (assoc.item1 ?? 0);
|
|
249
|
-
const value = metadataMap.get(sourceMid) ?? '';
|
|
250
|
-
return { mid: targetMid, value };
|
|
251
|
-
});
|
|
243
|
+
return mapRelationAssociationsToMids(relation, type, focusedItem);
|
|
252
244
|
}, [focusedItem]);
|
|
253
245
|
const archiveRelatedDcmtHandler = useCallback(async (relation, type) => {
|
|
254
246
|
const targetTID = type === 'detail' ? relation.detailTID : relation.masterTID;
|
|
@@ -537,6 +529,7 @@ export const useRelatedDocuments = ({ selectedSearchResult, focusedItem, current
|
|
|
537
529
|
dcmtsReturned: pairedDocumentsResult.dtdResult.rows.length,
|
|
538
530
|
dcmtsFound: pairedDocumentsResult.dtdResult.rows.length
|
|
539
531
|
};
|
|
532
|
+
setPairSearchContext(undefined);
|
|
540
533
|
setPairedSearchResults([pairedSq]);
|
|
541
534
|
setIsPairingManyToMany(isPairing);
|
|
542
535
|
setShowPairDcmtsModal(true);
|
|
@@ -578,6 +571,7 @@ export const useRelatedDocuments = ({ selectedSearchResult, focusedItem, current
|
|
|
578
571
|
openPairSearchModal(relation, targetTID, qd);
|
|
579
572
|
return;
|
|
580
573
|
}
|
|
574
|
+
setPairSearchContext({ relation, targetTID, qd });
|
|
581
575
|
setPairedSearchResults([filteredSq]);
|
|
582
576
|
setIsPairingManyToMany(isPairing);
|
|
583
577
|
setShowPairDcmtsModal(true);
|
|
@@ -652,6 +646,7 @@ export const useRelatedDocuments = ({ selectedSearchResult, focusedItem, current
|
|
|
652
646
|
selectedManyToManyRelation,
|
|
653
647
|
showManyToManyChooser,
|
|
654
648
|
manyToManyChooserDataSource,
|
|
649
|
+
backToPairSearchModal,
|
|
655
650
|
showPairSearchModal,
|
|
656
651
|
pairSearchModalTargetTID,
|
|
657
652
|
pairSearchModalParentTID,
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Impostazione avanzata "Mostra pratiche V5": le pratiche (i dossier) sono
|
|
3
|
+
* sostituite dal CaseFlow e restano nascoste finché l'utente non le riattiva.
|
|
4
|
+
*
|
|
5
|
+
* Il valore vive in `SDKUI_Globals.userSettings.advancedSettings`, quindi la
|
|
6
|
+
* persistenza è quella delle altre impostazioni utente (per archivio e utente).
|
|
7
|
+
*/
|
|
8
|
+
export declare const SHOW_DOSSIERS_V5_CHANGED_EVENT = "showDossiersV5Changed";
|
|
9
|
+
export declare const getShowDossiersV5: () => boolean;
|
|
10
|
+
export declare const setShowDossiersV5: (value: boolean) => void;
|
|
11
|
+
/** Legge l'impostazione e si aggiorna quando cambia. */
|
|
12
|
+
export declare const useShowDossiersV5: () => boolean;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
|
+
import { SDK_Globals } from '@topconsultnpm/sdk-ts';
|
|
3
|
+
import { SDKUI_Globals } from '../helper';
|
|
4
|
+
/**
|
|
5
|
+
* Impostazione avanzata "Mostra pratiche V5": le pratiche (i dossier) sono
|
|
6
|
+
* sostituite dal CaseFlow e restano nascoste finché l'utente non le riattiva.
|
|
7
|
+
*
|
|
8
|
+
* Il valore vive in `SDKUI_Globals.userSettings.advancedSettings`, quindi la
|
|
9
|
+
* persistenza è quella delle altre impostazioni utente (per archivio e utente).
|
|
10
|
+
*/
|
|
11
|
+
export const SHOW_DOSSIERS_V5_CHANGED_EVENT = 'showDossiersV5Changed';
|
|
12
|
+
export const getShowDossiersV5 = () => {
|
|
13
|
+
return SDKUI_Globals.userSettings.advancedSettings?.showDossiersV5 === 1;
|
|
14
|
+
};
|
|
15
|
+
export const setShowDossiersV5 = (value) => {
|
|
16
|
+
SDKUI_Globals.userSettings.advancedSettings.showDossiersV5 = value ? 1 : 0;
|
|
17
|
+
// Il setter di AdvancedSettings emette l'evento, ma dopo un ricaricamento
|
|
18
|
+
// della pagina `advancedSettings` torna da localStorage come oggetto
|
|
19
|
+
// semplice e non lo emette più: lo lanciamo anche qui, così i consumatori
|
|
20
|
+
// non dipendono da quale delle due forme è in memoria.
|
|
21
|
+
globalThis.dispatchEvent(new CustomEvent(SHOW_DOSSIERS_V5_CHANGED_EVENT, { detail: value }));
|
|
22
|
+
};
|
|
23
|
+
/** Legge l'impostazione e si aggiorna quando cambia. */
|
|
24
|
+
export const useShowDossiersV5 = () => {
|
|
25
|
+
const sessionDescr = SDK_Globals.tmSession?.SessionDescr;
|
|
26
|
+
const archiveId = sessionDescr?.archiveID;
|
|
27
|
+
const userId = sessionDescr?.userID;
|
|
28
|
+
const [showDossiersV5, setValue] = useState(getShowDossiersV5);
|
|
29
|
+
// Le impostazioni sono per utente e archivio: al cambio sessione va riletto.
|
|
30
|
+
useEffect(() => { setValue(getShowDossiersV5()); }, [archiveId, userId]);
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
const onChanged = () => setValue(getShowDossiersV5());
|
|
33
|
+
globalThis.addEventListener(SHOW_DOSSIERS_V5_CHANGED_EVENT, onChanged);
|
|
34
|
+
return () => globalThis.removeEventListener(SHOW_DOSSIERS_V5_CHANGED_EVENT, onChanged);
|
|
35
|
+
}, []);
|
|
36
|
+
return showDossiersV5;
|
|
37
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { MetadataDescriptor } from '@topconsultnpm/sdk-ts';
|
|
2
|
+
import { IColumnProps } from 'devextreme-react/data-grid';
|
|
3
|
+
export declare const needsDisplayValue: (columnMd: MetadataDescriptor | undefined) => boolean;
|
|
4
|
+
/**
|
|
5
|
+
* Resa dei valori nelle griglie di TMDistinctValues: al posto della chiave archiviata mostra la descrizione
|
|
6
|
+
* presa dalle cache di liste dati e utenti, tenendole allineate alle colonne effettivamente visualizzate.
|
|
7
|
+
*
|
|
8
|
+
* Vale per entrambe le sorgenti del pannello (valori distinti e ricerca rapida, che può essere su un altro
|
|
9
|
+
* tipo documento): le chiavi delle due sorgenti vengono accumulate e ricaricate sempre insieme, altrimenti
|
|
10
|
+
* un caricamento farebbe perdere le descrizioni dell'altra sorgente.
|
|
11
|
+
*/
|
|
12
|
+
export declare const useTMDistinctValuesMetadataDisplay: () => {
|
|
13
|
+
loadDisplayCachesAsync: (columnsMd: Array<MetadataDescriptor | undefined>, rows: string[][] | undefined) => Promise<void>;
|
|
14
|
+
getMetadataDisplayValue: (columnMd: MetadataDescriptor | undefined, value: any) => any;
|
|
15
|
+
displayValueColumnProps: (columnMd: MetadataDescriptor | undefined, dataField: string) => Partial<IColumnProps>;
|
|
16
|
+
};
|
|
17
|
+
/** Tipo di ritorno dell'hook: le sorgenti di TMDistinctValues lo ricevono come dipendenza */
|
|
18
|
+
export type TMDistinctValuesMetadataDisplay = ReturnType<typeof useTMDistinctValuesMetadataDisplay>;
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback, useRef } from 'react';
|
|
3
|
+
import { DataListViewModes, MetadataDataDomains } from '@topconsultnpm/sdk-ts';
|
|
4
|
+
import { SDKUI_Localizator, stringIsNullOrEmpty } from '../helper';
|
|
5
|
+
import { useDataListItem } from './useDataListItem';
|
|
6
|
+
import { useDataUserIdItem } from './useDataUserIdItem';
|
|
7
|
+
// Le griglie di TMDistinctValues mostrano la descrizione, non la chiave archiviata (es. TD01 -> FATTURA)
|
|
8
|
+
export const needsDisplayValue = (columnMd) => columnMd?.dataDomain === MetadataDataDomains.DataList || columnMd?.dataDomain === MetadataDataDomains.UserID;
|
|
9
|
+
const getCellDataListViewMode = (columnMd) => columnMd?.dataListViewMode === DataListViewModes.Description
|
|
10
|
+
? DataListViewModes.Description
|
|
11
|
+
: DataListViewModes.ImageAndDescription;
|
|
12
|
+
/**
|
|
13
|
+
* Resa dei valori nelle griglie di TMDistinctValues: al posto della chiave archiviata mostra la descrizione
|
|
14
|
+
* presa dalle cache di liste dati e utenti, tenendole allineate alle colonne effettivamente visualizzate.
|
|
15
|
+
*
|
|
16
|
+
* Vale per entrambe le sorgenti del pannello (valori distinti e ricerca rapida, che può essere su un altro
|
|
17
|
+
* tipo documento): le chiavi delle due sorgenti vengono accumulate e ricaricate sempre insieme, altrimenti
|
|
18
|
+
* un caricamento farebbe perdere le descrizioni dell'altra sorgente.
|
|
19
|
+
*/
|
|
20
|
+
export const useTMDistinctValuesMetadataDisplay = () => {
|
|
21
|
+
const { loadDataListsAsync, renderDataListCell, getDataListItem, hasDataList } = useDataListItem();
|
|
22
|
+
const { loadUsersAsync, renderUserIdViewer, getUserItem, getCompleteUserName, hasUser } = useDataUserIdItem();
|
|
23
|
+
// Le cache vengono sostituite con le sole chiavi richieste a ogni caricamento: qui si accumula l'insieme completo
|
|
24
|
+
const requestedDataListIDsRef = useRef(new Set());
|
|
25
|
+
const requestedUserIDsRef = useRef(new Set());
|
|
26
|
+
// I caricamenti delle due sorgenti possono sovrapporsi: la coda garantisce che l'ultimo a scrivere nelle cache sia quello con l'insieme completo di chiavi
|
|
27
|
+
const displayCachesQueueRef = useRef(Promise.resolve());
|
|
28
|
+
/** Le descrizioni vengono dalle cache di liste dati e utenti: vanno caricate prima di mostrare le righe */
|
|
29
|
+
const loadDisplayCachesAsync = useCallback(async (columnsMd, rows) => {
|
|
30
|
+
const dataListIDs = new Set();
|
|
31
|
+
const userIDs = new Set();
|
|
32
|
+
columnsMd.forEach((columnMd, index) => {
|
|
33
|
+
if (columnMd?.dataDomain === MetadataDataDomains.DataList && columnMd.dataListID) {
|
|
34
|
+
dataListIDs.add(columnMd.dataListID);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
if (columnMd?.dataDomain !== MetadataDataDomains.UserID)
|
|
38
|
+
return;
|
|
39
|
+
// Della cache utenti serve solo chi compare effettivamente nelle righe
|
|
40
|
+
rows?.forEach((row) => {
|
|
41
|
+
const userId = Number(row[index]);
|
|
42
|
+
if (userId && userId > 0)
|
|
43
|
+
userIDs.add(userId);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
if (dataListIDs.size <= 0 && userIDs.size <= 0)
|
|
47
|
+
return;
|
|
48
|
+
// In coda al caricamento precedente: l'insieme delle chiavi va calcolato quando è il turno di questa richiesta
|
|
49
|
+
const load = displayCachesQueueRef.current.then(async () => {
|
|
50
|
+
// Se tutte le chiavi richieste sono già in cache non c'è nulla da ricaricare
|
|
51
|
+
const isCacheComplete = Array.from(dataListIDs).every(id => hasDataList(id)) && Array.from(userIDs).every(id => hasUser(id));
|
|
52
|
+
if (isCacheComplete)
|
|
53
|
+
return;
|
|
54
|
+
dataListIDs.forEach(id => requestedDataListIDsRef.current.add(id));
|
|
55
|
+
userIDs.forEach(id => requestedUserIDsRef.current.add(id));
|
|
56
|
+
// Ricaricate tutte insieme: il caricamento sostituisce il contenuto delle cache
|
|
57
|
+
if (requestedDataListIDsRef.current.size > 0)
|
|
58
|
+
await loadDataListsAsync(new Set(requestedDataListIDsRef.current));
|
|
59
|
+
if (requestedUserIDsRef.current.size > 0)
|
|
60
|
+
await loadUsersAsync(new Set(requestedUserIDsRef.current));
|
|
61
|
+
});
|
|
62
|
+
// La coda non deve interrompersi per un caricamento fallito
|
|
63
|
+
displayCachesQueueRef.current = load.catch(() => { });
|
|
64
|
+
await load;
|
|
65
|
+
}, [loadDataListsAsync, loadUsersAsync, hasDataList, hasUser]);
|
|
66
|
+
const renderMetadataCell = useCallback((columnMd, cellData) => {
|
|
67
|
+
if (!cellData || cellData.value === undefined)
|
|
68
|
+
return null;
|
|
69
|
+
if (columnMd?.dataDomain === MetadataDataDomains.DataList && columnMd.dataListID) {
|
|
70
|
+
return renderDataListCell(cellData.value, columnMd.dataListID, getCellDataListViewMode(columnMd));
|
|
71
|
+
}
|
|
72
|
+
if (columnMd?.dataDomain === MetadataDataDomains.UserID) {
|
|
73
|
+
return renderUserIdViewer(Number(cellData.value), true);
|
|
74
|
+
}
|
|
75
|
+
return _jsx("div", { children: cellData.text });
|
|
76
|
+
}, [renderDataListCell, renderUserIdViewer]);
|
|
77
|
+
/** Descrizione da mostrare al posto della chiave archiviata, fuori dal contesto di una cella di griglia */
|
|
78
|
+
const getMetadataDisplayValue = useCallback((columnMd, value) => {
|
|
79
|
+
if (stringIsNullOrEmpty(value))
|
|
80
|
+
return value;
|
|
81
|
+
if (columnMd?.dataDomain === MetadataDataDomains.DataList && columnMd.dataListID) {
|
|
82
|
+
return getDataListItem(columnMd.dataListID, value)?.name ?? value;
|
|
83
|
+
}
|
|
84
|
+
if (columnMd?.dataDomain === MetadataDataDomains.UserID) {
|
|
85
|
+
const userId = Number(value);
|
|
86
|
+
if (userId === 0)
|
|
87
|
+
return SDKUI_Localizator.SystemUser;
|
|
88
|
+
const ud = getUserItem(userId);
|
|
89
|
+
return ud ? getCompleteUserName(ud.domain, ud.name) ?? value : value;
|
|
90
|
+
}
|
|
91
|
+
return value;
|
|
92
|
+
}, [getDataListItem, getUserItem, getCompleteUserName]);
|
|
93
|
+
/** Proprietà con cui una colonna mostra la descrizione al posto della chiave archiviata: vuote per i domini che non ne hanno bisogno */
|
|
94
|
+
const displayValueColumnProps = useCallback((columnMd, dataField) => {
|
|
95
|
+
if (!needsDisplayValue(columnMd))
|
|
96
|
+
return {};
|
|
97
|
+
return {
|
|
98
|
+
cellRender: (cellData) => renderMetadataCell(columnMd, cellData),
|
|
99
|
+
calculateDisplayValue: (rowData) => getMetadataDisplayValue(columnMd, rowData?.[dataField]),
|
|
100
|
+
};
|
|
101
|
+
}, [renderMetadataCell, getMetadataDisplayValue]);
|
|
102
|
+
return { loadDisplayCachesAsync, getMetadataDisplayValue, displayValueColumnProps };
|
|
103
|
+
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { MetadataDescriptor } from '@topconsultnpm/sdk-ts';
|
|
2
|
+
import { IColumnProps } from 'devextreme-react/data-grid';
|
|
3
|
+
import { DistinctValuesQuickSearchSettings } from '../helper';
|
|
4
|
+
import { TMDistinctValuesCounts } from './useTMDistinctValuesSource';
|
|
5
|
+
import { TMDistinctValuesMetadataDisplay } from './useTMDistinctValuesMetadataDisplay';
|
|
6
|
+
/** Le due sorgenti da cui TMDistinctValues può prelevare il valore del campo */
|
|
7
|
+
export declare enum DistinctValuesModes {
|
|
8
|
+
DistinctValues = 0,
|
|
9
|
+
QuickSearch = 1
|
|
10
|
+
}
|
|
11
|
+
/** Classe applicata alla colonna del metadato configurato nella ricerca rapida: è quella da cui si prende il valore */
|
|
12
|
+
export declare const QUICK_SEARCH_VALUE_COLUMN_CLASS = "tm-quick-search-value-column";
|
|
13
|
+
interface ITMDistinctValuesQuickSearchParams {
|
|
14
|
+
tid: number | undefined;
|
|
15
|
+
mid: number | undefined;
|
|
16
|
+
/** Metadato del campo, dalla sorgente dei valori distinti: è il ripiego quando la ricerca rapida non è attiva */
|
|
17
|
+
md: MetadataDescriptor | undefined;
|
|
18
|
+
display: TMDistinctValuesMetadataDisplay;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Sorgente "ricerca rapida" di TMDistinctValues, con il selettore di modalità del pannello: la modalità esiste
|
|
22
|
+
* solo perché esiste questa sorgente, quindi le due cose vivono insieme.
|
|
23
|
+
*
|
|
24
|
+
* La ricerca rapida non filtra i valori distinti: è una sorgente alternativa da cui prelevare il valore del
|
|
25
|
+
* metadato configurato nelle impostazioni, che restano associate alla coppia (tid, mid).
|
|
26
|
+
*/
|
|
27
|
+
export declare const useTMDistinctValuesQuickSearch: ({ tid, mid, md, display }: ITMDistinctValuesQuickSearchParams) => {
|
|
28
|
+
mode: DistinctValuesModes;
|
|
29
|
+
isQuickSearchMode: boolean;
|
|
30
|
+
isQuickSearchGridVisible: boolean;
|
|
31
|
+
isFirstSearchPending: boolean;
|
|
32
|
+
settings: DistinctValuesQuickSearchSettings | undefined;
|
|
33
|
+
columns: IColumnProps[];
|
|
34
|
+
dataSource: any[];
|
|
35
|
+
counts: TMDistinctValuesCounts;
|
|
36
|
+
customizeColumns: (columns: Array<any>) => void;
|
|
37
|
+
valueField: string | undefined;
|
|
38
|
+
selectedValueMd: MetadataDescriptor | undefined;
|
|
39
|
+
showSettingsForm: boolean;
|
|
40
|
+
setShowSettingsForm: import("react").Dispatch<import("react").SetStateAction<boolean>>;
|
|
41
|
+
onModeChanged: (newMode: DistinctValuesModes) => void;
|
|
42
|
+
onSaveSettings: (newSettings: DistinctValuesQuickSearchSettings) => void;
|
|
43
|
+
onDeleteSettings: () => void;
|
|
44
|
+
onDeleteSettingsClick: () => void;
|
|
45
|
+
onSettingsFormClose: () => void;
|
|
46
|
+
refreshAsync: () => Promise<void>;
|
|
47
|
+
ConfirmQueryParamsDialog: () => JSX.Element;
|
|
48
|
+
};
|
|
49
|
+
export {};
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
2
|
+
import { DataColumnTypes, DcmtTypeListCacheService, SavedQueryCacheService, SDK_Globals, SDK_Localizator, SearchEngine, SelectItemVisibilities, SystemMIDsAsNumber } from '@topconsultnpm/sdk-ts';
|
|
3
|
+
import { customizeSearchByDisplayText, generateUniqueColumnKeys, getColumnFormatInfo, getDateDisplayText, getDistinctValuesQuickSearch, getSysAllDcmtsSQD, IsParametricQuery, prepareQdForSearchAsync, removeDistinctValuesQuickSearch, saveDistinctValuesQuickSearch, searchResultDescriptorToSimpleArray, SDKUI_Localizator, stringIsNullOrEmpty, SYS_ALL_DCMTS_SQD_ID } from '../helper';
|
|
4
|
+
import ShowAlert from '../components/base/TMAlert';
|
|
5
|
+
import { ButtonNames, TMExceptionBoxManager, TMMessageBoxManager } from '../components/base/TMPopUp';
|
|
6
|
+
import TMSpinner from '../components/base/TMSpinner';
|
|
7
|
+
import { getColumnMid, getDateDisplayFormat, getMetadataName, toGridDataType, withRowIndex } from './tmDistinctValuesGridHelper';
|
|
8
|
+
import { needsDisplayValue } from './useTMDistinctValuesMetadataDisplay';
|
|
9
|
+
import { useQueryParametersDialog } from './useQueryParametersDialog';
|
|
10
|
+
/** Le due sorgenti da cui TMDistinctValues può prelevare il valore del campo */
|
|
11
|
+
export var DistinctValuesModes;
|
|
12
|
+
(function (DistinctValuesModes) {
|
|
13
|
+
DistinctValuesModes[DistinctValuesModes["DistinctValues"] = 0] = "DistinctValues";
|
|
14
|
+
DistinctValuesModes[DistinctValuesModes["QuickSearch"] = 1] = "QuickSearch";
|
|
15
|
+
})(DistinctValuesModes || (DistinctValuesModes = {}));
|
|
16
|
+
/** Classe applicata alla colonna del metadato configurato nella ricerca rapida: è quella da cui si prende il valore */
|
|
17
|
+
export const QUICK_SEARCH_VALUE_COLUMN_CLASS = 'tm-quick-search-value-column';
|
|
18
|
+
// Sostituisce i segnaposto dei parametri con i valori confermati dall'utente
|
|
19
|
+
const applyQueryParams = (qd, qdParams) => {
|
|
20
|
+
for (const qpd of qdParams) {
|
|
21
|
+
const value = !qpd.value ? '' : qpd.value.toString();
|
|
22
|
+
let wi = qd.where?.find(o => o.value1 === qpd.name);
|
|
23
|
+
if (wi) {
|
|
24
|
+
wi.value1 = value;
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
wi = qd.where?.find(o => o.value2 === qpd.name);
|
|
28
|
+
if (wi)
|
|
29
|
+
wi.value2 = value;
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Sorgente "ricerca rapida" di TMDistinctValues, con il selettore di modalità del pannello: la modalità esiste
|
|
34
|
+
* solo perché esiste questa sorgente, quindi le due cose vivono insieme.
|
|
35
|
+
*
|
|
36
|
+
* La ricerca rapida non filtra i valori distinti: è una sorgente alternativa da cui prelevare il valore del
|
|
37
|
+
* metadato configurato nelle impostazioni, che restano associate alla coppia (tid, mid).
|
|
38
|
+
*/
|
|
39
|
+
export const useTMDistinctValuesQuickSearch = ({ tid, mid, md, display }) => {
|
|
40
|
+
const { loadDisplayCachesAsync, displayValueColumnProps, getMetadataDisplayValue } = display;
|
|
41
|
+
// L'impostazione configurata per il campo va letta già al primo render: leggerla solo nell'effect farebbe nascere
|
|
42
|
+
// il pannello nella modalità dei valori distinti, per poi passare alla ricerca rapida sotto gli occhi dell'utente
|
|
43
|
+
const savedSettings = getDistinctValuesQuickSearch(tid, mid);
|
|
44
|
+
const [mode, setMode] = useState(savedSettings ? DistinctValuesModes.QuickSearch : DistinctValuesModes.DistinctValues);
|
|
45
|
+
const [settings, setSettings] = useState(savedSettings);
|
|
46
|
+
const [showSettingsForm, setShowSettingsForm] = useState(false);
|
|
47
|
+
const [result, setResult] = useState();
|
|
48
|
+
// Metadato di ciascuna colonna del risultato, nello stesso ordine delle colonne
|
|
49
|
+
const [columnsMd, setColumnsMd] = useState([]);
|
|
50
|
+
// Impostazione per cui la ricerca è già stata portata a termine, con o senza risultato: finché non coincide con
|
|
51
|
+
// quella corrente il risultato non è ancora noto, e con esso le colonne da cui dipende la larghezza del pannello
|
|
52
|
+
const [completedSettings, setCompletedSettings] = useState();
|
|
53
|
+
const [confirmQueryParams, ConfirmQueryParamsDialog] = useQueryParametersDialog();
|
|
54
|
+
// Identifica la richiesta corrente: dopo ogni await le risposte delle richieste obsolete vengono scartate
|
|
55
|
+
const requestIdRef = useRef(0);
|
|
56
|
+
// Ultimi parametri confermati: vengono riproposti alla successiva esecuzione della stessa ricerca
|
|
57
|
+
const lastQdParamsRef = useRef([]);
|
|
58
|
+
const isQuickSearchMode = mode === DistinctValuesModes.QuickSearch;
|
|
59
|
+
// Finché l'impostazione non è stata salvata restano visibili i valori distinti: la griglia della ricerca rapida sarebbe vuota
|
|
60
|
+
const isQuickSearchGridVisible = isQuickSearchMode && !!settings;
|
|
61
|
+
/** La prima ricerca per l'impostazione corrente non è ancora conclusa: le colonne del risultato non sono note */
|
|
62
|
+
const isFirstSearchPending = isQuickSearchGridVisible && completedSettings !== settings;
|
|
63
|
+
// Cambiando campo va ripresa l'impostazione configurata per la nuova coppia (tid, mid)
|
|
64
|
+
useEffect(() => {
|
|
65
|
+
const fieldQuickSearch = getDistinctValuesQuickSearch(tid, mid);
|
|
66
|
+
setSettings(fieldQuickSearch);
|
|
67
|
+
// Se il campo ha una ricerca rapida configurata è quella la sorgente da mostrare, non i valori distinti
|
|
68
|
+
setMode(fieldQuickSearch ? DistinctValuesModes.QuickSearch : DistinctValuesModes.DistinctValues);
|
|
69
|
+
setResult(undefined);
|
|
70
|
+
setColumnsMd([]);
|
|
71
|
+
setCompletedSettings(undefined);
|
|
72
|
+
lastQdParamsRef.current = [];
|
|
73
|
+
}, [tid, mid]);
|
|
74
|
+
// I valori distinti restano in memoria dopo il primo caricamento, la ricerca rapida va eseguita a ogni cambio di impostazione
|
|
75
|
+
useEffect(() => {
|
|
76
|
+
if (!isQuickSearchMode || !settings)
|
|
77
|
+
return;
|
|
78
|
+
runAsync(settings);
|
|
79
|
+
}, [mode, settings]);
|
|
80
|
+
const runAsync = async (currentSettings) => {
|
|
81
|
+
// Impostazione incompleta: non c'è nulla da eseguire, ma il pannello non deve restare in attesa del risultato
|
|
82
|
+
if (!currentSettings.tid || !currentSettings.sqdId) {
|
|
83
|
+
setCompletedSettings(currentSettings);
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
const requestId = ++requestIdRef.current;
|
|
87
|
+
const isStale = () => requestId !== requestIdRef.current;
|
|
88
|
+
setResult(undefined);
|
|
89
|
+
setColumnsMd([]);
|
|
90
|
+
try {
|
|
91
|
+
const sqd = currentSettings.sqdId === SYS_ALL_DCMTS_SQD_ID
|
|
92
|
+
? await getSysAllDcmtsSQD(currentSettings.tid, false)
|
|
93
|
+
: await SavedQueryCacheService.GetAsync(currentSettings.sqdId);
|
|
94
|
+
const qd = SearchEngine.NormalizeQueryDescriptor(sqd?.qd);
|
|
95
|
+
if (!qd) {
|
|
96
|
+
// La ricerca salvata può essere stata eliminata o non essere più accessibile: senza avviso il pannello resterebbe vuoto senza spiegazione
|
|
97
|
+
if (isStale())
|
|
98
|
+
return;
|
|
99
|
+
ShowAlert({ mode: 'warning', title: SDK_Localizator.SavedQuery, message: 'La ricerca rapida configurata non è più disponibile: modificare le impostazioni', duration: 4000 });
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
const qdSearch = await prepareQdForSearchAsync(qd, sqd?.isEasyWhere === 1);
|
|
103
|
+
qdSearch.maxDcmtsToBeReturned = currentSettings.maxDcmtsToBeReturned;
|
|
104
|
+
qdSearch.select?.forEach(o => { o.visibility ??= SelectItemVisibilities.Visible; });
|
|
105
|
+
// Una ricerca parametrica non è eseguibile senza i valori dei parametri: vengono chiesti all'utente
|
|
106
|
+
if (IsParametricQuery(qdSearch)) {
|
|
107
|
+
const qdParams = await confirmQueryParams(qdSearch, lastQdParamsRef.current);
|
|
108
|
+
if (!qdParams || qdParams.length <= 0)
|
|
109
|
+
return;
|
|
110
|
+
lastQdParamsRef.current = qdParams;
|
|
111
|
+
applyQueryParams(qdSearch, qdParams);
|
|
112
|
+
}
|
|
113
|
+
TMSpinner.show({ description: `${SDKUI_Localizator.Search} ...` });
|
|
114
|
+
const searchResult = await SDK_Globals.tmSession?.NewSearchEngine().SearchByIDAsync(qdSearch);
|
|
115
|
+
if (isStale())
|
|
116
|
+
return;
|
|
117
|
+
if ((searchResult?.dcmtsFound ?? 0) <= 0)
|
|
118
|
+
ShowAlert({ mode: 'warning', title: SDKUI_Localizator.SearchResult, message: SDKUI_Localizator.NoDcmtFound, duration: 3000 });
|
|
119
|
+
const resultColumnsMd = await loadColumnsMdAsync(currentSettings.tid, searchResult);
|
|
120
|
+
if (isStale())
|
|
121
|
+
return;
|
|
122
|
+
setColumnsMd(resultColumnsMd);
|
|
123
|
+
setResult(searchResult);
|
|
124
|
+
}
|
|
125
|
+
catch (e) {
|
|
126
|
+
if (isStale())
|
|
127
|
+
return;
|
|
128
|
+
TMExceptionBoxManager.show({ exception: e });
|
|
129
|
+
}
|
|
130
|
+
finally {
|
|
131
|
+
TMSpinner.hide();
|
|
132
|
+
// Anche senza risultato la ricerca è conclusa: il pannello va mostrato, è da lì che si correggono le impostazioni
|
|
133
|
+
if (!isStale())
|
|
134
|
+
setCompletedSettings(currentSettings);
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
// Risolve ogni colonna del risultato nel proprio metadato e carica le cache (liste dati, utenti) necessarie a mostrarne la descrizione
|
|
138
|
+
const loadColumnsMdAsync = async (searchTid, searchResult) => {
|
|
139
|
+
const columns = searchResult?.dtdResult?.columns ?? [];
|
|
140
|
+
if (columns.length <= 0)
|
|
141
|
+
return [];
|
|
142
|
+
const dtd = await DcmtTypeListCacheService.GetAsync(searchTid, true);
|
|
143
|
+
const resultColumnsMd = columns.map((col, index) => dtd?.metadata?.find(o => o.id === getColumnMid(col, searchResult?.selectMIDs, index)));
|
|
144
|
+
await loadDisplayCachesAsync(resultColumnsMd, searchResult?.dtdResult?.rows);
|
|
145
|
+
return resultColumnsMd;
|
|
146
|
+
};
|
|
147
|
+
const refreshAsync = async () => { if (settings)
|
|
148
|
+
await runAsync(settings); };
|
|
149
|
+
const columnKeys = useMemo(() => generateUniqueColumnKeys(result?.dtdResult?.columns, result?.fromTID), [result]);
|
|
150
|
+
/** Individua il campo della griglia corrispondente a un metadato del risultato */
|
|
151
|
+
const findField = useCallback((targetMid) => {
|
|
152
|
+
const columns = result?.dtdResult?.columns;
|
|
153
|
+
if (!columns || !targetMid)
|
|
154
|
+
return undefined;
|
|
155
|
+
let columnIndex = columns.findIndex(col => Number(col.extendedProperties?.['MID'] ?? 0) === targetMid);
|
|
156
|
+
// Senza le proprietà estese resta l'allineamento posizionale tra selectMIDs e colonne del risultato
|
|
157
|
+
if (columnIndex < 0)
|
|
158
|
+
columnIndex = result?.selectMIDs?.indexOf(targetMid) ?? -1;
|
|
159
|
+
return columnIndex >= 0 ? columnKeys[columnIndex] : undefined;
|
|
160
|
+
}, [result, columnKeys]);
|
|
161
|
+
// Righe dalla più recente alla meno recente: conta la data di ultima modifica, in mancanza quella di creazione
|
|
162
|
+
const dataSource = useMemo(() => {
|
|
163
|
+
const rows = searchResultDescriptorToSimpleArray(result) ?? [];
|
|
164
|
+
const lastUpdateField = findField(SystemMIDsAsNumber.LastUpdateTime);
|
|
165
|
+
const creationField = findField(SystemMIDsAsNumber.CreationTime);
|
|
166
|
+
if (!lastUpdateField && !creationField)
|
|
167
|
+
return rows;
|
|
168
|
+
const getRowTime = (item) => {
|
|
169
|
+
const value = (lastUpdateField ? item?.[lastUpdateField] : undefined) || (creationField ? item?.[creationField] : undefined);
|
|
170
|
+
if (stringIsNullOrEmpty(value))
|
|
171
|
+
return undefined;
|
|
172
|
+
const time = new Date(value).getTime();
|
|
173
|
+
return Number.isNaN(time) ? undefined : time;
|
|
174
|
+
};
|
|
175
|
+
rows.sort((a, b) => {
|
|
176
|
+
const timeA = getRowTime(a);
|
|
177
|
+
const timeB = getRowTime(b);
|
|
178
|
+
// Le righe prive di entrambe le date finiscono in fondo, nel loro ordine originale
|
|
179
|
+
if (timeA === undefined)
|
|
180
|
+
return timeB === undefined ? 0 : 1;
|
|
181
|
+
if (timeB === undefined)
|
|
182
|
+
return -1;
|
|
183
|
+
return timeB - timeA;
|
|
184
|
+
});
|
|
185
|
+
return withRowIndex(rows);
|
|
186
|
+
}, [result, findField]);
|
|
187
|
+
/** Il valore da riportare nel campo è quello della colonna del metadato configurato nelle impostazioni */
|
|
188
|
+
const valueField = useMemo(() => findField(settings?.mid), [findField, settings?.mid]);
|
|
189
|
+
/** Metadato da cui viene prelevato il valore: nel riepilogo serve per mostrarne la descrizione al posto della chiave archiviata */
|
|
190
|
+
const selectedValueMd = useMemo(() => {
|
|
191
|
+
if (!isQuickSearchGridVisible)
|
|
192
|
+
return md;
|
|
193
|
+
const columnIndex = valueField ? columnKeys.indexOf(valueField) : -1;
|
|
194
|
+
return columnIndex >= 0 ? columnsMd[columnIndex] : undefined;
|
|
195
|
+
}, [isQuickSearchGridVisible, md, valueField, columnKeys, columnsMd]);
|
|
196
|
+
const columns = useMemo(() => {
|
|
197
|
+
const resultColumns = result?.dtdResult?.columns?.map((col, index) => {
|
|
198
|
+
const columnMd = columnsMd[index];
|
|
199
|
+
const dataField = columnKeys[index];
|
|
200
|
+
// È la colonna da cui viene prelevato il valore: va sempre in evidenza e non può restare nascosta
|
|
201
|
+
const isValueColumn = !!valueField && dataField === valueField;
|
|
202
|
+
// Formato e cultura di visualizzazione definiti sulle proprietà estese della colonna
|
|
203
|
+
const { format, formatCulture } = getColumnFormatInfo(col);
|
|
204
|
+
// Il MID risolve l'intestazione quando la didascalia del risultato è assente
|
|
205
|
+
const columnMid = getColumnMid(col, result?.selectMIDs, index);
|
|
206
|
+
return {
|
|
207
|
+
dataField: dataField,
|
|
208
|
+
// Nell'intestazione va il nome del metadato: la didascalia del risultato può essere assente e lascerebbe la colonna senza nome
|
|
209
|
+
caption: getMetadataName(columnMd) ?? col.caption ?? (columnMid ? `MID ${columnMid}` : undefined),
|
|
210
|
+
// I metadati di sistema aggiunti alla query restano nel risultato ma non vanno mostrati
|
|
211
|
+
visible: isValueColumn || col.extendedProperties?.['Visibility'] !== 'Hidden',
|
|
212
|
+
// Dalla selezione colonne non deve essere possibile nascondere la colonna del valore
|
|
213
|
+
allowHiding: !isValueColumn,
|
|
214
|
+
cssClass: isValueColumn ? QUICK_SEARCH_VALUE_COLUMN_CLASS : undefined,
|
|
215
|
+
dataType: toGridDataType(col.dataType),
|
|
216
|
+
format: col.dataType === DataColumnTypes.DateTime ? getDateDisplayFormat(format, formatCulture) : '',
|
|
217
|
+
...displayValueColumnProps(columnMd, dataField)
|
|
218
|
+
};
|
|
219
|
+
}) ?? [];
|
|
220
|
+
// La colonna del metadato configurato va in testa: è quella da cui si preleva il valore
|
|
221
|
+
const valueColumnIndex = valueField ? resultColumns.findIndex(col => col.dataField === valueField) : -1;
|
|
222
|
+
if (valueColumnIndex > 0) {
|
|
223
|
+
const [valueColumn] = resultColumns.splice(valueColumnIndex, 1);
|
|
224
|
+
resultColumns.unshift(valueColumn);
|
|
225
|
+
}
|
|
226
|
+
return resultColumns;
|
|
227
|
+
}, [result, columnKeys, columnsMd, valueField, displayValueColumnProps]);
|
|
228
|
+
// Date formattate e descrizioni di liste dati/utenti: la ricerca va fatta sul testo mostrato, non sul valore archiviato
|
|
229
|
+
const searchTextGetters = useMemo(() => {
|
|
230
|
+
const getters = new Map();
|
|
231
|
+
result?.dtdResult?.columns?.forEach((col, index) => {
|
|
232
|
+
const dataField = columnKeys[index];
|
|
233
|
+
if (!dataField)
|
|
234
|
+
return;
|
|
235
|
+
if (col.dataType === DataColumnTypes.DateTime) {
|
|
236
|
+
const { format, formatCulture } = getColumnFormatInfo(col);
|
|
237
|
+
getters.set(dataField, (rowData) => getDateDisplayText(rowData?.[dataField], format, formatCulture));
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
const columnMd = columnsMd[index];
|
|
241
|
+
if (needsDisplayValue(columnMd)) {
|
|
242
|
+
getters.set(dataField, (rowData) => String(getMetadataDisplayValue(columnMd, rowData?.[dataField]) ?? ''));
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
return getters;
|
|
246
|
+
}, [result, columnKeys, columnsMd, getMetadataDisplayValue]);
|
|
247
|
+
const customizeColumns = useMemo(() => customizeSearchByDisplayText(searchTextGetters), [searchTextGetters]);
|
|
248
|
+
const counts = useMemo(() => ({ returned: result?.dcmtsReturned ?? 0, found: result?.dcmtsFound ?? 0 }), [result]);
|
|
249
|
+
// Senza la colonna del metadato configurato la selezione di una riga non produrrebbe alcun valore
|
|
250
|
+
useEffect(() => {
|
|
251
|
+
if (!isQuickSearchGridVisible)
|
|
252
|
+
return;
|
|
253
|
+
if (isFirstSearchPending)
|
|
254
|
+
return;
|
|
255
|
+
if (!result?.dtdResult?.rows?.length)
|
|
256
|
+
return;
|
|
257
|
+
if (valueField)
|
|
258
|
+
return;
|
|
259
|
+
ShowAlert({ mode: 'warning', title: SDK_Localizator.SavedQuery, message: 'La ricerca rapida selezionata non restituisce il metadato configurato', duration: 4000 });
|
|
260
|
+
}, [isQuickSearchGridVisible, isFirstSearchPending, result, valueField]);
|
|
261
|
+
const onModeChanged = (newMode) => {
|
|
262
|
+
setMode(newMode);
|
|
263
|
+
// Senza impostazione salvata la ricerca rapida non è utilizzabile: si chiede subito come configurarla
|
|
264
|
+
if (newMode === DistinctValuesModes.QuickSearch && !settings)
|
|
265
|
+
setShowSettingsForm(true);
|
|
266
|
+
};
|
|
267
|
+
const onSaveSettings = (newSettings) => {
|
|
268
|
+
// L'impostazione resta configurata per il campo: viene ripresa alla prossima apertura del pannello
|
|
269
|
+
saveDistinctValuesQuickSearch(tid, mid, newSettings);
|
|
270
|
+
// I parametri della ricerca precedente non valgono per la nuova ricerca
|
|
271
|
+
lastQdParamsRef.current = [];
|
|
272
|
+
setSettings(newSettings);
|
|
273
|
+
setShowSettingsForm(false);
|
|
274
|
+
};
|
|
275
|
+
const onDeleteSettings = () => {
|
|
276
|
+
removeDistinctValuesQuickSearch(tid, mid);
|
|
277
|
+
lastQdParamsRef.current = [];
|
|
278
|
+
setSettings(undefined);
|
|
279
|
+
setResult(undefined);
|
|
280
|
+
setColumnsMd([]);
|
|
281
|
+
setShowSettingsForm(false);
|
|
282
|
+
// Senza impostazione la ricerca rapida non è utilizzabile: si torna ai valori distinti
|
|
283
|
+
setMode(DistinctValuesModes.DistinctValues);
|
|
284
|
+
};
|
|
285
|
+
const onDeleteSettingsClick = () => {
|
|
286
|
+
TMMessageBoxManager.show({
|
|
287
|
+
title: SDKUI_Localizator.Delete,
|
|
288
|
+
message: SDKUI_Localizator.QuickSearchSettings_DeleteConfirmFor1.replaceParams(getMetadataName(md) ?? SDK_Localizator.Metadata),
|
|
289
|
+
buttons: [ButtonNames.YES, ButtonNames.NO],
|
|
290
|
+
onButtonClick: (e) => { if (e === ButtonNames.YES)
|
|
291
|
+
onDeleteSettings(); }
|
|
292
|
+
});
|
|
293
|
+
};
|
|
294
|
+
const onSettingsFormClose = () => {
|
|
295
|
+
setShowSettingsForm(false);
|
|
296
|
+
// Senza impostazione la ricerca rapida non è utilizzabile: si torna ai valori distinti
|
|
297
|
+
if (!settings)
|
|
298
|
+
setMode(DistinctValuesModes.DistinctValues);
|
|
299
|
+
};
|
|
300
|
+
return {
|
|
301
|
+
mode, isQuickSearchMode, isQuickSearchGridVisible, isFirstSearchPending,
|
|
302
|
+
settings, columns, dataSource, counts, customizeColumns, valueField, selectedValueMd,
|
|
303
|
+
showSettingsForm, setShowSettingsForm,
|
|
304
|
+
onModeChanged, onSaveSettings, onDeleteSettings, onDeleteSettingsClick, onSettingsFormClose,
|
|
305
|
+
refreshAsync, ConfirmQueryParamsDialog
|
|
306
|
+
};
|
|
307
|
+
};
|