@topconsultnpm/sdkui-react 6.22.0-dev2.17 → 6.22.0-dev2.18

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.
Files changed (40) hide show
  1. package/lib/components/base/TMEditorBase.d.ts +2 -0
  2. package/lib/components/base/TMTooltip.d.ts +2 -1
  3. package/lib/components/base/TMTooltip.js +23 -6
  4. package/lib/components/choosers/TMDcmtTypeChooser.js +4 -3
  5. package/lib/components/choosers/TMDistinctValues.d.ts +9 -7
  6. package/lib/components/choosers/TMDistinctValues.js +147 -195
  7. package/lib/components/choosers/TMMetadataChooser.js +1 -1
  8. package/lib/components/choosers/TMQuickSearchInfo.d.ts +12 -0
  9. package/lib/components/choosers/TMQuickSearchInfo.js +279 -0
  10. package/lib/components/choosers/TMQuickSearchSettingsForm.d.ts +16 -0
  11. package/lib/components/choosers/TMQuickSearchSettingsForm.js +94 -0
  12. package/lib/components/choosers/TMSelectedValuesSummary.d.ts +13 -0
  13. package/lib/components/choosers/TMSelectedValuesSummary.js +91 -0
  14. package/lib/components/editors/TMDropDown.d.ts +3 -0
  15. package/lib/components/editors/TMDropDown.js +197 -5
  16. package/lib/components/features/search/TMSearchResult.js +55 -4
  17. package/lib/components/viewers/TMMidViewer.js +4 -1
  18. package/lib/components/viewers/TMTidViewer.js +25 -11
  19. package/lib/helper/SDKUI_Globals.d.ts +20 -0
  20. package/lib/helper/SDKUI_Globals.js +44 -0
  21. package/lib/helper/SDKUI_Localizator.d.ts +1 -0
  22. package/lib/helper/SDKUI_Localizator.js +10 -0
  23. package/lib/helper/dataGridSearchHelper.d.ts +28 -0
  24. package/lib/helper/dataGridSearchHelper.js +51 -0
  25. package/lib/helper/index.d.ts +1 -0
  26. package/lib/helper/index.js +1 -0
  27. package/lib/helper/queryHelper.d.ts +2 -0
  28. package/lib/helper/queryHelper.js +3 -1
  29. package/lib/hooks/tmDistinctValuesGridHelper.d.ts +16 -0
  30. package/lib/hooks/tmDistinctValuesGridHelper.js +31 -0
  31. package/lib/hooks/useTMDistinctValuesMetadataDisplay.d.ts +18 -0
  32. package/lib/hooks/useTMDistinctValuesMetadataDisplay.js +103 -0
  33. package/lib/hooks/useTMDistinctValuesQuickSearch.d.ts +49 -0
  34. package/lib/hooks/useTMDistinctValuesQuickSearch.js +307 -0
  35. package/lib/hooks/useTMDistinctValuesSelection.d.ts +42 -0
  36. package/lib/hooks/useTMDistinctValuesSelection.js +103 -0
  37. package/lib/hooks/useTMDistinctValuesSource.d.ts +29 -0
  38. package/lib/hooks/useTMDistinctValuesSource.js +105 -0
  39. package/lib/services/platform_services.d.ts +1 -1
  40. package/package.json +1 -1
@@ -1,11 +1,13 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useState } from "react";
3
- import styled from "styled-components";
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useRef, useState } from "react";
3
+ import { createPortal } from "react-dom";
4
+ import styled, { css } from "styled-components";
4
5
  import { FontSize, TMColors } from '../../utils/theme';
5
6
  import { StyledEditorContainer, StyledEditorIcon, StyledEditorLabel, TMEditorsDefaultBorderRadius, editorColorManager } from "./TMEditorStyled";
6
7
  import TMLayoutContainer, { TMLayoutItem } from "../base/TMLayout";
7
8
  import TMVilViewer from "../base/TMVilViewer";
8
9
  import TMTooltip from "../base/TMTooltip";
10
+ import { SDKUI_Localizator } from "../../helper";
9
11
  const StyledDropDownWrapper = styled.div `
10
12
  position: relative;
11
13
  width: ${props => props.$width};
@@ -54,9 +56,199 @@ const StyledDropDownEditorButton = styled.div `
54
56
  align-items: center;
55
57
  cursor: pointer;
56
58
  `;
57
- const TMDropDown = ({ validationItems = [], disabled = false, elementStyle, isModifiedWhen, labelPosition = 'left', label, icon, width = '100%', fontSize = FontSize.defaultFontSize, dataSource, value, onValueChanged, buttons = [], placeHolder, }) => {
59
+ // Variante filtrabile: un input di testo con la stessa resa grafica della select nativa
60
+ const StyledSearchInput = styled.input `
61
+ width: 100%;
62
+ padding: 5px 35px 3px 9px;
63
+ border: 1px solid;
64
+ border-color: ${props => props.$isModified ? TMColors.isModified : TMColors.border_normal};
65
+ border-bottom: ${props => (props.$vil.length > 0) ? '3px' : '1px'} solid;
66
+ border-bottom-color: ${props => (props.$vil.length === 0) ? !props.$isModified ? TMColors.border_normal : TMColors.isModified : editorColorManager(props.$vil)};
67
+ color: ${props => !props.$disabled ? (props.$vil.length === 0 ? (!props.$isModified ? TMColors.text_normal : TMColors.isModified) : editorColorManager(props.$vil)) : TMColors.disabled};
68
+ border-radius: ${props => props.$borderRadius ?? TMEditorsDefaultBorderRadius};
69
+ font-size: ${props => props.$fontSize};
70
+ background-color: ${props => props.$disabled ? '#F5F5F5' : 'white'};
71
+ text-overflow: ellipsis;
72
+
73
+ &:focus {
74
+ outline: none;
75
+ border: ${props => props.$isModified ? `1px solid ${TMColors.isModified}` : '1px solid rgb(180,180,180)'};
76
+ border-bottom: 2px solid;
77
+ border-bottom-color: ${props => (props.$vil.length === 0) ? !props.$isModified ? TMColors.primary : TMColors.isModified : editorColorManager(props.$vil)};
78
+ }
79
+ `;
80
+ const OPTIONS_PANEL_MAX_HEIGHT = 220;
81
+ const OPTIONS_PANEL_MIN_HEIGHT = 80;
82
+ const OPTIONS_PANEL_MARGIN = 4;
83
+ // L'elenco aperto con usePortal esce dal contenitore dell'editor: deve stare sopra tutto ciò che può trovarsi nella stessa pagina
84
+ const DROPDOWN_OPTIONS_PANEL_Z_INDEX = 100001;
85
+ const optionsPanelCss = css `
86
+ overflow-y: auto;
87
+ background-color: white;
88
+ border: 1px solid ${TMColors.border_normal};
89
+ border-radius: ${TMEditorsDefaultBorderRadius};
90
+ box-shadow: 0 4px 10px rgba(0, 0, 0, 0.15);
91
+ `;
92
+ // Elenco ancorato all'editor: resta nel flusso del DOM e quindi soggetto al clipping dei contenitori con overflow
93
+ const StyledOptionsPanel = styled.div `
94
+ ${optionsPanelCss}
95
+ position: absolute;
96
+ top: calc(100% + 2px);
97
+ left: 0;
98
+ right: 0;
99
+ z-index: 10001;
100
+ max-height: ${OPTIONS_PANEL_MAX_HEIGHT}px;
101
+ `;
102
+ // Variante usePortal: posizione calcolata rispetto alla finestra, così l'elenco non viene tagliato da nessun contenitore
103
+ const StyledPortalOptionsPanel = styled.div `
104
+ ${optionsPanelCss}
105
+ position: fixed;
106
+ left: ${props => props.$left}px;
107
+ ${props => props.$top !== undefined ? `top: ${props.$top}px;` : ''}
108
+ ${props => props.$bottom !== undefined ? `bottom: ${props.$bottom}px;` : ''}
109
+ width: ${props => props.$width}px;
110
+ z-index: ${DROPDOWN_OPTIONS_PANEL_Z_INDEX};
111
+ max-height: ${props => props.$maxHeight}px;
112
+ `;
113
+ const StyledOption = styled.div `
114
+ padding: 5px 9px;
115
+ font-size: ${props => props.$fontSize};
116
+ cursor: pointer;
117
+ white-space: nowrap;
118
+ overflow: hidden;
119
+ text-overflow: ellipsis;
120
+ font-weight: ${props => props.$isSelected ? 600 : 'normal'};
121
+ background-color: ${props => props.$isHighlighted ? TMColors.primary_container : 'transparent'};
122
+ `;
123
+ const StyledNoOptions = styled.div `
124
+ padding: 5px 9px;
125
+ font-size: ${props => props.$fontSize};
126
+ color: ${TMColors.disabled};
127
+ `;
128
+ // L'elenco si apre sotto l'editor se c'è spazio, altrimenti sopra, e in ogni caso non esce dalla finestra
129
+ const calcOptionsPanelPosition = (rect) => {
130
+ const spaceBelow = window.innerHeight - rect.bottom - OPTIONS_PANEL_MARGIN;
131
+ const spaceAbove = rect.top - OPTIONS_PANEL_MARGIN;
132
+ const openUpwards = spaceBelow < OPTIONS_PANEL_MAX_HEIGHT && spaceAbove > spaceBelow;
133
+ const availableHeight = openUpwards ? spaceAbove : spaceBelow;
134
+ return {
135
+ left: Math.max(OPTIONS_PANEL_MARGIN, Math.min(rect.left, window.innerWidth - rect.width - OPTIONS_PANEL_MARGIN)),
136
+ top: openUpwards ? undefined : rect.bottom + OPTIONS_PANEL_MARGIN,
137
+ bottom: openUpwards ? window.innerHeight - rect.top + OPTIONS_PANEL_MARGIN : undefined,
138
+ width: rect.width,
139
+ maxHeight: Math.max(OPTIONS_PANEL_MIN_HEIGHT, Math.min(OPTIONS_PANEL_MAX_HEIGHT, availableHeight)),
140
+ };
141
+ };
142
+ const TMDropDown = ({ validationItems = [], disabled = false, elementStyle, isModifiedWhen, labelPosition = 'left', label, icon, width = '100%', fontSize = FontSize.defaultFontSize, dataSource, value, searchEnabled = false, usePortal = false, itemRender, onValueChanged, buttons = [], placeHolder, }) => {
58
143
  const [isFocused, setIsFocused] = useState(false);
59
- const renderedLeftLabelTextBox = () => (_jsxs(TMLayoutContainer, { direction: 'horizontal', children: [icon && _jsx(TMLayoutItem, { width: '20px', children: _jsx(StyledEditorIcon, { "$disabled": disabled, "$vil": validationItems, "$isModified": isModifiedWhen, children: icon }) }), _jsx(TMLayoutItem, { children: _jsxs(StyledEditorContainer, { "$width": width, children: [label && _jsx(StyledEditorLabel, { "$isFocused": isFocused, "$labelPosition": labelPosition, "$disabled": disabled, children: label }), _jsxs(StyledDropDownWrapper, { "$width": width, children: [_jsxs(StyledDropDown, { value: value, onFocus: () => setIsFocused(true), onBlur: () => setIsFocused(false), "$disabled": disabled, disabled: disabled, "$fontSize": fontSize, "$isModified": isModifiedWhen, "$vil": validationItems, onChange: onValueChanged, children: [placeHolder && _jsx("option", { value: "", disabled: true, hidden: true, children: placeHolder }), dataSource?.map((data, index) => (_jsx("option", { value: data.value, children: data.display }, index)))] }), buttons.length > 0 && (_jsx(ButtonsContainer, { children: buttons.map((buttonItem) => (_jsx(StyledDropDownEditorButton, { onClick: buttonItem.onClick, children: _jsx(TMTooltip, { content: buttonItem.text, children: buttonItem.icon }) }, buttonItem.text))) })), _jsx(CustomArrow, {})] }), _jsx(TMVilViewer, { vil: validationItems })] }) })] }));
144
+ const [isOpen, setIsOpen] = useState(false);
145
+ const [searchText, setSearchText] = useState('');
146
+ const [highlightedIndex, setHighlightedIndex] = useState(-1);
147
+ const [optionsPanelPosition, setOptionsPanelPosition] = useState();
148
+ const optionsPanelRef = useRef(null);
149
+ const dropDownWrapperRef = useRef(null);
150
+ const selectedItem = dataSource?.find(o => String(o.value) === String(value));
151
+ // A elenco chiuso l'input mostra la voce selezionata, ad elenco aperto il testo digitato
152
+ const filteredDataSource = (!isOpen || !searchText) ? (dataSource ?? []) : (dataSource ?? []).filter(o => String(o.display ?? '').toLocaleLowerCase().includes(searchText.toLocaleLowerCase()));
153
+ // Mantiene visibile la voce evidenziata durante la navigazione da tastiera
154
+ useEffect(() => {
155
+ if (!isOpen || highlightedIndex < 0)
156
+ return;
157
+ const option = optionsPanelRef.current?.children[highlightedIndex];
158
+ option?.scrollIntoView({ block: 'nearest' });
159
+ }, [isOpen, highlightedIndex]);
160
+ // Solo nel portal la posizione va ricalcolata: essendo fissa non segue lo scorrimento o il ridimensionamento del contenitore
161
+ useEffect(() => {
162
+ if (!isOpen || !usePortal)
163
+ return;
164
+ const updatePosition = () => updateOptionsPanelPosition();
165
+ window.addEventListener('scroll', updatePosition, true);
166
+ window.addEventListener('resize', updatePosition);
167
+ return () => {
168
+ window.removeEventListener('scroll', updatePosition, true);
169
+ window.removeEventListener('resize', updatePosition);
170
+ };
171
+ }, [isOpen, usePortal]);
172
+ const updateOptionsPanelPosition = () => {
173
+ const rect = dropDownWrapperRef.current?.getBoundingClientRect();
174
+ if (rect)
175
+ setOptionsPanelPosition(calcOptionsPanelPosition(rect));
176
+ };
177
+ const openOptions = () => {
178
+ if (disabled)
179
+ return;
180
+ if (usePortal)
181
+ updateOptionsPanelPosition();
182
+ setIsOpen(true);
183
+ setSearchText('');
184
+ setHighlightedIndex(dataSource?.findIndex(o => String(o.value) === String(value)) ?? -1);
185
+ };
186
+ const closeOptions = () => {
187
+ setIsOpen(false);
188
+ setSearchText('');
189
+ setHighlightedIndex(-1);
190
+ };
191
+ const selectItem = (item) => {
192
+ closeOptions();
193
+ // La select nativa notifica un ChangeEvent: qui viene ricostruito il solo dato letto dai consumatori (target.value)
194
+ onValueChanged?.({ target: { value: String(item.value) } });
195
+ };
196
+ const onSearchKeyDown = (e) => {
197
+ switch (e.key) {
198
+ case 'ArrowDown':
199
+ case 'ArrowUp':
200
+ e.preventDefault();
201
+ if (!isOpen) {
202
+ openOptions();
203
+ return;
204
+ }
205
+ if (filteredDataSource.length <= 0)
206
+ return;
207
+ setHighlightedIndex(prev => {
208
+ const delta = e.key === 'ArrowDown' ? 1 : -1;
209
+ const next = prev + delta;
210
+ if (next < 0)
211
+ return filteredDataSource.length - 1;
212
+ if (next >= filteredDataSource.length)
213
+ return 0;
214
+ return next;
215
+ });
216
+ break;
217
+ case 'Enter': {
218
+ if (!isOpen)
219
+ return;
220
+ e.preventDefault();
221
+ const item = filteredDataSource[highlightedIndex] ?? filteredDataSource[0];
222
+ if (item)
223
+ selectItem(item);
224
+ break;
225
+ }
226
+ case 'Escape':
227
+ if (isOpen) {
228
+ e.preventDefault();
229
+ closeOptions();
230
+ }
231
+ break;
232
+ }
233
+ };
234
+ const renderOptions = () => (filteredDataSource.length > 0
235
+ ? filteredDataSource.map((data, index) => (_jsx(StyledOption, { "$fontSize": fontSize, "$isSelected": String(data.value) === String(value), "$isHighlighted": index === highlightedIndex, onMouseEnter: () => setHighlightedIndex(index), onClick: () => selectItem(data), children: itemRender ? itemRender(data) : data.display }, index)))
236
+ : _jsx(StyledNoOptions, { "$fontSize": fontSize, children: SDKUI_Localizator.NoDataToDisplay }));
237
+ // onMouseDown va bloccato: senza preventDefault il blur dell'input chiuderebbe l'elenco prima del click
238
+ const renderOptionsPanel = () => {
239
+ if (!isOpen)
240
+ return null;
241
+ if (!usePortal) {
242
+ return (_jsx(StyledOptionsPanel, { ref: optionsPanelRef, onMouseDown: (e) => e.preventDefault(), children: renderOptions() }));
243
+ }
244
+ if (!optionsPanelPosition)
245
+ return null;
246
+ return createPortal(_jsx(StyledPortalOptionsPanel, { ref: optionsPanelRef, "$left": optionsPanelPosition.left, "$top": optionsPanelPosition.top, "$bottom": optionsPanelPosition.bottom, "$width": optionsPanelPosition.width, "$maxHeight": optionsPanelPosition.maxHeight, onMouseDown: (e) => e.preventDefault(), children: renderOptions() }), document.body);
247
+ };
248
+ const renderSearchableDropDown = () => (_jsxs(_Fragment, { children: [_jsx(StyledSearchInput, { value: isOpen ? searchText : (selectedItem?.display ?? ''), placeholder: isOpen ? SDKUI_Localizator.Search : placeHolder, readOnly: disabled, disabled: disabled, "$disabled": disabled, "$fontSize": fontSize, "$isModified": isModifiedWhen, "$vil": validationItems, onFocus: () => { setIsFocused(true); openOptions(); }, onBlur: () => { setIsFocused(false); closeOptions(); }, onClick: () => { if (!isOpen)
249
+ openOptions(); }, onChange: (e) => { setSearchText(e.target.value); setIsOpen(true); setHighlightedIndex(0); }, onKeyDown: onSearchKeyDown }), renderOptionsPanel()] }));
250
+ const renderNativeDropDown = () => (_jsxs(StyledDropDown, { value: value, onFocus: () => setIsFocused(true), onBlur: () => setIsFocused(false), "$disabled": disabled, disabled: disabled, "$fontSize": fontSize, "$isModified": isModifiedWhen, "$vil": validationItems, onChange: onValueChanged, children: [placeHolder && _jsx("option", { value: "", disabled: true, hidden: true, children: placeHolder }), dataSource?.map((data, index) => (_jsx("option", { value: data.value, children: data.display }, index)))] }));
251
+ const renderedLeftLabelTextBox = () => (_jsxs(TMLayoutContainer, { direction: 'horizontal', children: [icon && _jsx(TMLayoutItem, { width: '20px', children: _jsx(StyledEditorIcon, { "$disabled": disabled, "$vil": validationItems, "$isModified": isModifiedWhen, children: icon }) }), _jsx(TMLayoutItem, { children: _jsxs(StyledEditorContainer, { "$width": width, children: [label && _jsx(StyledEditorLabel, { "$isFocused": isFocused, "$labelPosition": labelPosition, "$disabled": disabled, children: label }), _jsxs(StyledDropDownWrapper, { ref: dropDownWrapperRef, "$width": width, children: [searchEnabled ? renderSearchableDropDown() : renderNativeDropDown(), buttons.length > 0 && (_jsx(ButtonsContainer, { children: buttons.map((buttonItem) => (_jsx(StyledDropDownEditorButton, { onClick: buttonItem.onClick, children: _jsx(TMTooltip, { content: buttonItem.tooltipContent ?? buttonItem.text, children: buttonItem.icon }) }, buttonItem.text))) })), _jsx(CustomArrow, {})] }), _jsx(TMVilViewer, { vil: validationItems })] }) })] }));
60
252
  return _jsx("div", { style: elementStyle, children: renderedLeftLabelTextBox() });
61
253
  };
62
254
  export default TMDropDown;
@@ -3,7 +3,7 @@ import React, { useCallback, useEffect, useMemo, useRef, useState } 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, IconMenuVertical, IconPlatform, IconRefresh, IconSearchCheck, IconShow, isApprovalWorkflowView, isSign4TopEnabled, searchResultDescriptorToSimpleArray, searchResultToMetadataValues, SDKUI_Globals, SDKUI_Localizator } from '../../../helper';
7
7
  import { CounterItemKey } from '../../base/TMCounterContainer';
8
8
  import { getDcmtCicoStatus } from '../../../helper/checkinCheckoutManager';
9
9
  import { DcmtOperationTypes, SearchResultContext, } from '../../../ts';
@@ -926,8 +926,8 @@ const TMSearchResultGrid = ({ openInOffice, fromDTD, operationItems, allUsers, i
926
926
  useEffect(() => {
927
927
  updateDataSourceFromDataGrid(dataSource ?? []);
928
928
  }, [dataSource]);
929
- const { loadDataListsAsync, renderDataListCell, dataListsCache } = useDataListItem();
930
- const { loadUsersAsync, renderUserIdViewer, usersCache } = useDataUserIdItem();
929
+ const { loadDataListsAsync, renderDataListCell, dataListsCache, getDataListItem } = useDataListItem();
930
+ const { loadUsersAsync, renderUserIdViewer, usersCache, getUserItem, getCompleteUserName } = useDataUserIdItem();
931
931
  useEffect(() => {
932
932
  // Sincronizza focusedItem con inputFocusedItem dal padre
933
933
  if (deepCompare(inputFocusedItem, focusedItem))
@@ -1159,6 +1159,57 @@ const TMSearchResultGrid = ({ openInOffice, fromDTD, operationItems, allUsers, i
1159
1159
  });
1160
1160
  return cols;
1161
1161
  }, [searchResult, dataType, cellRender, getDisplayFormat, dataListsCache, usersCache]);
1162
+ /**
1163
+ * Colonne in cui il testo mostrato è diverso dal valore archiviato: date e numeri formattati, descrizioni
1164
+ * di liste dati e utenti. Su queste la ricerca della griglia va fatta sul testo mostrato, altrimenti non
1165
+ * trova nulla (es. cercando 29/01/2023 su una data, che nei dati è una stringa ISO).
1166
+ * Le cache sono ref lette al momento della ricerca: a quel punto sono già popolate.
1167
+ */
1168
+ const searchTextGetters = useMemo(() => {
1169
+ const getters = new Map();
1170
+ const columnsOfResult = searchResult?.dtdResult?.columns;
1171
+ if (!columnsOfResult)
1172
+ return getters;
1173
+ const uniqueKeys = generateUniqueColumnKeys(columnsOfResult, searchResult?.fromTID);
1174
+ columnsOfResult.forEach((col, index) => {
1175
+ const dataField = uniqueKeys[index];
1176
+ if (!dataField)
1177
+ return;
1178
+ const dataDomain = MetadataDataDomains[(col.extendedProperties?.["DataDomain"] ?? "None")];
1179
+ const dataListID = Number(col.extendedProperties?.["DataListID"]);
1180
+ if (dataDomain === MetadataDataDomains.DataList && dataListID) {
1181
+ getters.set(dataField, (rowData) => getDataListItem(dataListID, rowData?.[dataField])?.name ?? String(rowData?.[dataField] ?? ''));
1182
+ return;
1183
+ }
1184
+ if (dataDomain === MetadataDataDomains.UserID) {
1185
+ getters.set(dataField, (rowData) => {
1186
+ const rawValue = rowData?.[dataField];
1187
+ // Un campo utente vuoto non mostra nulla: senza questo controllo Number('') darebbe 0, cioè l'utente di sistema
1188
+ if (rawValue === undefined || rawValue === null || rawValue === '')
1189
+ return '';
1190
+ const userId = Number(rawValue);
1191
+ if (Number.isNaN(userId))
1192
+ return String(rawValue);
1193
+ if (userId === 0)
1194
+ return SDKUI_Localizator.SystemUser ?? '';
1195
+ const ud = getUserItem(userId);
1196
+ return (ud ? getCompleteUserName(ud.domain, ud.name) : undefined) ?? String(rawValue);
1197
+ });
1198
+ return;
1199
+ }
1200
+ // Data e numero vengono mostrati con il formato definito sulle proprietà estese della colonna
1201
+ const { format, formatCulture } = getColumnFormatInfo(col);
1202
+ if (col.dataType === DataColumnTypes.DateTime) {
1203
+ getters.set(dataField, (rowData) => getDateDisplayText(rowData?.[dataField], format, formatCulture));
1204
+ return;
1205
+ }
1206
+ if (col.dataType === DataColumnTypes.Number) {
1207
+ getters.set(dataField, (rowData) => getNumberDisplayText(rowData?.[dataField], format, formatCulture));
1208
+ }
1209
+ });
1210
+ return getters;
1211
+ }, [searchResult, getDataListItem, getUserItem, getCompleteUserName]);
1212
+ const customizeColumns = useMemo(() => customizeSearchByDisplayText(searchTextGetters), [searchTextGetters]);
1162
1213
  /**
1163
1214
  * Effect che carica i dati necessari e genera le colonne della griglia.
1164
1215
  * Esegue il caricamento delle cache (DataList e UserID) in parallelo prima di generare le colonne,
@@ -1289,7 +1340,7 @@ const TMSearchResultGrid = ({ openInOffice, fromDTD, operationItems, allUsers, i
1289
1340
  setVisibleItems(visibleData);
1290
1341
  }, []);
1291
1342
  useEffect(() => { onVisibleItemChanged?.(visibleItems); }, [visibleItems]);
1292
- 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, 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, onSelectionChanged: handleSelectionChange, onFocusedRowChanged: handleFocusedRowChange, onRowDblClick: onRowDblClick, onContentReady: onContentReady, showHeaderColumnChooser: true, onKeyDown: onKeyDown, customContextMenuItems: operationItems, counterConfig: {
1343
+ 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, onSelectionChanged: handleSelectionChange, onFocusedRowChanged: handleFocusedRowChange, onRowDblClick: onRowDblClick, onContentReady: onContentReady, showHeaderColumnChooser: true, onKeyDown: onKeyDown, customContextMenuItems: operationItems, counterConfig: {
1293
1344
  show: true,
1294
1345
  items: dcmtsReturned !== undefined && dcmtsFound !== undefined
1295
1346
  ? new Map([
@@ -92,8 +92,11 @@ export const TMMetadataIcon = ({ tid, md, color, layoutMode = LayoutModes.Update
92
92
  break;
93
93
  }
94
94
  }
95
+ // color='inherit' serve solo all'icona (eredita il colore dell'editor): il tooltip è renderizzato in overlay,
96
+ // dove 'inherit' non risolverebbe al colore dell'editor, quindi lì manteniamo la palette normale
97
+ let tooltipColor = color === 'inherit' ? undefined : color;
95
98
  return (_jsx(_Fragment, { children: icon
96
- ? _jsx(TMMetadataTooltip, { tid: tid, md: md, layoutMode: layoutMode, color: color, children: icon })
99
+ ? _jsx(TMMetadataTooltip, { tid: tid, md: md, layoutMode: layoutMode, color: tooltipColor, children: icon })
97
100
  : null }));
98
101
  };
99
102
  export const TMMetadataTooltip = ({ tid, md, color, children, layoutMode = LayoutModes.Update }) => {
@@ -259,7 +259,7 @@ export const TMDcmtTypeIcon = ({ dtd }) => {
259
259
  return (_jsx(TMDcmtTypeTooltip, { dtd: dtd, children: icon }));
260
260
  };
261
261
  export const TMDcmtTypeTooltip = ({ dtd, children }) => {
262
- return (_jsx("div", { style: { pointerEvents: 'all' }, children: _jsx(TMTooltip, { content: renderDTDTooltipContent(dtd), children: children }) }));
262
+ return (_jsx("div", { style: { pointerEvents: 'all' }, children: _jsx(TMTooltip, { allowContentInteraction: true, content: renderDTDTooltipContent(dtd), children: children }) }));
263
263
  };
264
264
  const TMTidViewer = ({ tmSession, tid, did, showIcon = false, color, showId = false, noneSelectionText = `<${SDKUI_Localizator.NoneSelection}>` }) => {
265
265
  const [dtd, setDtd] = useState();
@@ -297,29 +297,43 @@ const TMTidViewer = ({ tmSession, tid, did, showIcon = false, color, showId = fa
297
297
  textOverflow: 'ellipsis'
298
298
  }, children: [showIcon && dtd && _jsx(TMDcmtTypeIcon, { dtd: dtd }), _jsx("p", { title: displayName(), style: {
299
299
  textAlign: 'left',
300
+ margin: 0,
300
301
  marginLeft: showIcon ? '5px' : '',
301
- color: color ?? (dtd?.isView ? 'red' : TMColors.primary),
302
+ color: dtd?.isView ? 'red' : (color ?? TMColors.primary),
302
303
  whiteSpace: 'nowrap',
303
304
  overflow: 'hidden',
304
305
  textOverflow: 'ellipsis',
305
306
  // paddingRight: '10px'
306
- }, children: displayName() }), showId && _jsx("p", { style: { padding: '0px 3px' }, children: `(TID: ${tid})` })] }));
307
+ }, children: displayName() }), showId && _jsx("p", { style: { padding: '0px 3px', margin: 0 }, children: `(TID: ${tid})` })] }));
307
308
  };
308
309
  export default TMTidViewer;
309
310
  export const cellRenderTID = (data, noneSelectionText) => {
310
311
  return (_jsx(TMTidViewer, { tid: data.value, noneSelectionText: noneSelectionText }));
311
312
  };
312
- /** Componente per mostrare il metodo di visualizzazione del nome documento (carica i metadati dalla cache se necessario) */
313
+ /** Metodi di visualizzazione già richiesti, per non ricaricare i metadati ad ogni riapertura del tooltip */
314
+ const displayNameMethodCache = new Map();
313
315
  const TMDisplayNameMethodItem = ({ dtd }) => {
314
- const [displayNameMethod, setDisplayNameMethod] = useState('...');
315
- useEffect(() => {
316
- const fetchDisplayNameMethod = async () => {
316
+ const [displayNameMethod, setDisplayNameMethod] = useState(() => dtd.id ? displayNameMethodCache.get(dtd.id) : undefined);
317
+ const [isLoading, setIsLoading] = useState(false);
318
+ const onShowClick = async (e) => {
319
+ /* Un click qualsiasi chiude il tooltip: senza questo il risultato non sarebbe mai visibile */
320
+ e.stopPropagation();
321
+ if (isLoading || displayNameMethod)
322
+ return;
323
+ setIsLoading(true);
324
+ try {
317
325
  const method = await getDTDDisplayNameInfo(dtd);
326
+ if (dtd.id)
327
+ displayNameMethodCache.set(dtd.id, method);
318
328
  setDisplayNameMethod(method);
319
- };
320
- fetchDisplayNameMethod();
321
- }, [dtd]);
322
- return _jsx(StyledTooltipItem, { children: `${SDKUI_Localizator.DisplayNameMethod}: ${displayNameMethod}` });
329
+ }
330
+ finally {
331
+ setIsLoading(false);
332
+ }
333
+ };
334
+ return (_jsxs(StyledTooltipItem, { children: [`${SDKUI_Localizator.DisplayNameMethod}: `, displayNameMethod ?? (isLoading
335
+ ? `${SDKUI_Localizator.Loading} ...`
336
+ : _jsx("span", { style: { color: TMColors.primary, cursor: 'pointer', textDecoration: 'underline' }, onClick: onShowClick, children: SDKUI_Localizator.Details }))] }));
323
337
  };
324
338
  export const renderDTDTooltipContent = (dtd) => {
325
339
  const mapAccessLevelToLocalizedString = (level) => {
@@ -67,6 +67,18 @@ export declare class ThemeSettings {
67
67
  export declare const DEFAULT_PREVIEW_THRESHOLD = 500;
68
68
  export declare const DEFAULT_PAGE_SIZE = 100;
69
69
  export declare const DEFAULT_MAX_DCMTS_TO_BE_RETURNED = 200;
70
+ export declare const DEFAULT_QUICK_SEARCH_MAX_DCMTS = 1000;
71
+ /** Ricerca rapida configurata come sorgente alternativa dei valori distinti di un campo */
72
+ export declare class DistinctValuesQuickSearchSettings {
73
+ /** Tipo documento su cui viene eseguita la ricerca rapida */
74
+ tid: number | undefined;
75
+ /** ID della ricerca salvata (SavedQueryDescriptor) da eseguire; SYS_ALL_DCMTS_SQD_ID per la ricerca di sistema con tutti i documenti del tipo documento */
76
+ sqdId: number | undefined;
77
+ /** Metadato del risultato da cui viene prelevato il valore */
78
+ mid: number | undefined;
79
+ /** Numero massimo di documenti restituiti dalla ricerca rapida */
80
+ maxDcmtsToBeReturned: number;
81
+ }
70
82
  export declare class SearchSettings {
71
83
  autoFindReferences: ObjectClasses[];
72
84
  invoiceRetrieveFormat: InvoiceRetrieveFormats;
@@ -86,7 +98,15 @@ export declare class SearchSettings {
86
98
  };
87
99
  relationExpandLevel: number;
88
100
  relationShowZeroDcmts: boolean;
101
+ /** Ricerche rapide configurate per i valori distinti: una per ogni campo, con chiave "tid_mid" */
102
+ distinctValuesQuickSearches: {
103
+ [fieldKey: string]: DistinctValuesQuickSearchSettings;
104
+ };
89
105
  }
106
+ /** Ricerca rapida configurata per il campo, se presente */
107
+ export declare const getDistinctValuesQuickSearch: (tid: number | undefined, mid: number | undefined) => DistinctValuesQuickSearchSettings | undefined;
108
+ export declare const saveDistinctValuesQuickSearch: (tid: number | undefined, mid: number | undefined, settings: DistinctValuesQuickSearchSettings) => void;
109
+ export declare const removeDistinctValuesQuickSearch: (tid: number | undefined, mid: number | undefined) => void;
90
110
  export declare class FloatingMenuBarSettings {
91
111
  orientation?: 'horizontal' | 'vertical';
92
112
  itemIds?: string[];
@@ -130,6 +130,20 @@ export class ThemeSettings {
130
130
  export const DEFAULT_PREVIEW_THRESHOLD = 500; // KB
131
131
  export const DEFAULT_PAGE_SIZE = 100;
132
132
  export const DEFAULT_MAX_DCMTS_TO_BE_RETURNED = 200;
133
+ export const DEFAULT_QUICK_SEARCH_MAX_DCMTS = 1000;
134
+ /** Ricerca rapida configurata come sorgente alternativa dei valori distinti di un campo */
135
+ export class DistinctValuesQuickSearchSettings {
136
+ constructor() {
137
+ /** Tipo documento su cui viene eseguita la ricerca rapida */
138
+ this.tid = undefined;
139
+ /** ID della ricerca salvata (SavedQueryDescriptor) da eseguire; SYS_ALL_DCMTS_SQD_ID per la ricerca di sistema con tutti i documenti del tipo documento */
140
+ this.sqdId = undefined;
141
+ /** Metadato del risultato da cui viene prelevato il valore */
142
+ this.mid = undefined;
143
+ /** Numero massimo di documenti restituiti dalla ricerca rapida */
144
+ this.maxDcmtsToBeReturned = DEFAULT_QUICK_SEARCH_MAX_DCMTS;
145
+ }
146
+ }
133
147
  export class SearchSettings {
134
148
  constructor() {
135
149
  this.autoFindReferences = [];
@@ -144,8 +158,38 @@ export class SearchSettings {
144
158
  this.panelLayout = {};
145
159
  this.relationExpandLevel = 4; // Livello di espansione predefinito per le correlazioni
146
160
  this.relationShowZeroDcmts = false;
161
+ /** Ricerche rapide configurate per i valori distinti: una per ogni campo, con chiave "tid_mid" */
162
+ this.distinctValuesQuickSearches = {};
147
163
  }
148
164
  }
165
+ /** Il campo da cui viene aperto il pannello dei valori distinti è identificato dalla coppia (tid, mid) */
166
+ const distinctValuesFieldKey = (tid, mid) => `${tid}_${mid}`;
167
+ /** Ricerca rapida configurata per il campo, se presente */
168
+ export const getDistinctValuesQuickSearch = (tid, mid) => {
169
+ if (!tid || !mid)
170
+ return undefined;
171
+ // Le impostazioni salvate da versioni precedenti non hanno la mappa: va gestita l'assenza
172
+ return SDKUI_Globals.userSettings.searchSettings.distinctValuesQuickSearches?.[distinctValuesFieldKey(tid, mid)];
173
+ };
174
+ export const saveDistinctValuesQuickSearch = (tid, mid, settings) => {
175
+ if (!tid || !mid)
176
+ return;
177
+ // Il proxy delle impostazioni persiste solo intercettando l'assegnazione di una proprietà: la mappa va riassegnata per intero
178
+ SDKUI_Globals.userSettings.searchSettings.distinctValuesQuickSearches = {
179
+ ...SDKUI_Globals.userSettings.searchSettings.distinctValuesQuickSearches,
180
+ [distinctValuesFieldKey(tid, mid)]: settings,
181
+ };
182
+ };
183
+ export const removeDistinctValuesQuickSearch = (tid, mid) => {
184
+ if (!tid || !mid)
185
+ return;
186
+ const fieldKey = distinctValuesFieldKey(tid, mid);
187
+ const quickSearches = SDKUI_Globals.userSettings.searchSettings.distinctValuesQuickSearches;
188
+ if (!quickSearches?.[fieldKey])
189
+ return;
190
+ const { [fieldKey]: removedSettings, ...remainingQuickSearches } = quickSearches;
191
+ SDKUI_Globals.userSettings.searchSettings.distinctValuesQuickSearches = remainingQuickSearches;
192
+ };
149
193
  export class FloatingMenuBarSettings {
150
194
  }
151
195
  export class ArchivingSettings {
@@ -657,6 +657,7 @@ export declare class SDKUI_Localizator {
657
657
  static get QueryDefine(): "Abfrage definieren" | "Query define" | "Definir consulta" | "Défine query" | "Definir query" | "Definisci query";
658
658
  static get Query_EnterAlias(): "Geben Sie einen Alias ​​ein" | "Enter an alias" | "Introducir un alias" | "Entrez un alias" | "Digite um nome de alias" | "Inserire un alias";
659
659
  static get QueryParamBind(): "Query-Parameter erweitern" | "Fill query parameters" | "Valorizar parámetros consulta" | "Ajoute la valeur à les paramètres de la query" | "Melhora parâmetros de query" | "Valorizza parametri query";
660
+ static get QuickSearchSettings_DeleteConfirmFor1(): "Schnellsuche-Konfiguration für '{{0}}' löschen?" | "Delete the quick search setup for '{{0}}'?" | "¿Eliminar la configuración de la búsqueda rápida de '{{0}}'?" | "Supprimer la configuration de la recherche rapide de '{{0}}' ?" | "Eliminar a configuração da pesquisa rápida de '{{0}}'?" | "Eliminare la configurazione della ricerca rapida di '{{0}}'?";
660
661
  static get ReadOnly(): "Nur Lesen" | "Read only" | "Solo lectura" | "En lecture seule" | "Somente leitura" | "Solo lettura";
661
662
  static get Reassign(): "Neu zuweisen" | "Reassign" | "Reasignar" | "Réaffecter" | "Reatribuir" | "Riassegna";
662
663
  static get RefersTo(): string;
@@ -6542,6 +6542,16 @@ export class SDKUI_Localizator {
6542
6542
  default: return "Valorizza parametri query";
6543
6543
  }
6544
6544
  }
6545
+ static get QuickSearchSettings_DeleteConfirmFor1() {
6546
+ switch (this._cultureID) {
6547
+ case CultureIDs.De_DE: return "Schnellsuche-Konfiguration für '{{0}}' löschen?";
6548
+ case CultureIDs.En_US: return "Delete the quick search setup for '{{0}}'?";
6549
+ case CultureIDs.Es_ES: return "¿Eliminar la configuración de la búsqueda rápida de '{{0}}'?";
6550
+ case CultureIDs.Fr_FR: return "Supprimer la configuration de la recherche rapide de '{{0}}' ?";
6551
+ case CultureIDs.Pt_PT: return "Eliminar a configuração da pesquisa rápida de '{{0}}'?";
6552
+ default: return "Eliminare la configurazione della ricerca rapida di '{{0}}'?";
6553
+ }
6554
+ }
6545
6555
  static get ReadOnly() {
6546
6556
  switch (this._cultureID) {
6547
6557
  case CultureIDs.De_DE: return "Nur Lesen";
@@ -0,0 +1,28 @@
1
+ import { MetadataFormats } from '@topconsultnpm/sdk-ts';
2
+ /** Testo mostrato in una colonna per una riga: è quello su cui va cercato ciò che l'utente digita */
3
+ export type SearchTextGetter = (rowData: any) => string;
4
+ /** Testo con cui una data viene mostrata nella griglia: è quello che l'utente vede e quindi quello che cerca */
5
+ export declare const getDateDisplayText: (value: any, format: MetadataFormats | undefined, formatCulture: string | undefined | null) => string;
6
+ /** Testo con cui un numero viene mostrato nella griglia (separatore delle migliaia, valuta, decimali) */
7
+ export declare const getNumberDisplayText: (value: any, format: MetadataFormats | undefined, formatCulture: string) => string;
8
+ /**
9
+ * Dirotta la ricerca della griglia sul testo mostrato, per le colonne indicate (chiave: il `dataField`).
10
+ *
11
+ * La ricerca di DevExtreme lavora sul valore archiviato, quindi non trova nulla dove il testo mostrato è
12
+ * diverso:
13
+ * - **date**, che nei dati sono stringhe ISO: DevExtreme prova a interpretare il testo digitato con il
14
+ * formato della colonna, non riesce (il formato è un formatter personalizzato, non un pattern) e scarta
15
+ * la colonna dalla ricerca — cercando `29/01/2023` non trova nulla;
16
+ * - **numeri formattati**, per lo stesso motivo (separatore delle migliaia, simbolo di valuta);
17
+ * - **liste dati e utenti**, dove viene confrontata la chiave archiviata invece della descrizione
18
+ * visualizzata — cercando `FATTURA` non trova nulla, cercando `TD01` sì.
19
+ *
20
+ * Da passare a `customizeColumns` della griglia. Va fatto lì perché solo lì è disponibile la
21
+ * `calculateFilterExpression` predefinita di DevExtreme, che resta in uso per il filtro di intestazione e
22
+ * per il generatore di filtri: quelli funzionano già correttamente e vanno lasciati intatti.
23
+ *
24
+ * @example
25
+ * const searchTextGetters = useMemo(() => new Map([['TM_1_2', (row) => getDateDisplayText(row?.TM_1_2, format, culture)]]), [...]);
26
+ * const customizeColumns = useMemo(() => customizeSearchByDisplayText(searchTextGetters), [searchTextGetters]);
27
+ */
28
+ export declare const customizeSearchByDisplayText: (searchTextGetters: Map<string, SearchTextGetter>) => (columns: Array<any>) => void;
@@ -0,0 +1,51 @@
1
+ import { formatDateTimeByMetadataFormat, formatNumberByMetadataFormat } from './TMUtils';
2
+ /** Testo con cui una data viene mostrata nella griglia: è quello che l'utente vede e quindi quello che cerca */
3
+ export const getDateDisplayText = (value, format, formatCulture) => {
4
+ if (value === undefined || value === null || value === '')
5
+ return '';
6
+ const date = value instanceof Date ? value : new Date(value);
7
+ return Number.isNaN(date.getTime()) ? '' : formatDateTimeByMetadataFormat(date, format, formatCulture);
8
+ };
9
+ /** Testo con cui un numero viene mostrato nella griglia (separatore delle migliaia, valuta, decimali) */
10
+ export const getNumberDisplayText = (value, format, formatCulture) => {
11
+ if (value === undefined || value === null || value === '')
12
+ return '';
13
+ return formatNumberByMetadataFormat(value, format, formatCulture);
14
+ };
15
+ /**
16
+ * Dirotta la ricerca della griglia sul testo mostrato, per le colonne indicate (chiave: il `dataField`).
17
+ *
18
+ * La ricerca di DevExtreme lavora sul valore archiviato, quindi non trova nulla dove il testo mostrato è
19
+ * diverso:
20
+ * - **date**, che nei dati sono stringhe ISO: DevExtreme prova a interpretare il testo digitato con il
21
+ * formato della colonna, non riesce (il formato è un formatter personalizzato, non un pattern) e scarta
22
+ * la colonna dalla ricerca — cercando `29/01/2023` non trova nulla;
23
+ * - **numeri formattati**, per lo stesso motivo (separatore delle migliaia, simbolo di valuta);
24
+ * - **liste dati e utenti**, dove viene confrontata la chiave archiviata invece della descrizione
25
+ * visualizzata — cercando `FATTURA` non trova nulla, cercando `TD01` sì.
26
+ *
27
+ * Da passare a `customizeColumns` della griglia. Va fatto lì perché solo lì è disponibile la
28
+ * `calculateFilterExpression` predefinita di DevExtreme, che resta in uso per il filtro di intestazione e
29
+ * per il generatore di filtri: quelli funzionano già correttamente e vanno lasciati intatti.
30
+ *
31
+ * @example
32
+ * const searchTextGetters = useMemo(() => new Map([['TM_1_2', (row) => getDateDisplayText(row?.TM_1_2, format, culture)]]), [...]);
33
+ * const customizeColumns = useMemo(() => customizeSearchByDisplayText(searchTextGetters), [searchTextGetters]);
34
+ */
35
+ export const customizeSearchByDisplayText = (searchTextGetters) => (columns) => {
36
+ columns.forEach((column) => {
37
+ const getSearchText = column?.dataField ? searchTextGetters.get(column.dataField) : undefined;
38
+ // customizeColumns viene richiamata a ogni aggiornamento delle colonne: senza il marcatore i wrapper si anniderebbero
39
+ if (!getSearchText || column.tmSearchByDisplayText)
40
+ return;
41
+ const defaultCalculateFilterExpression = column.calculateFilterExpression;
42
+ // Senza questo DevExtreme prova a convertire il testo digitato nel tipo della colonna e, non riuscendo, la scarta
43
+ column.parseValue = (text) => text;
44
+ column.calculateFilterExpression = function (filterValue, selectedFilterOperation, target) {
45
+ if (target === 'search')
46
+ return [getSearchText, 'contains', filterValue];
47
+ return defaultCalculateFilterExpression?.apply(this, arguments);
48
+ };
49
+ column.tmSearchByDisplayText = true;
50
+ });
51
+ };
@@ -5,6 +5,7 @@ export * from './Globalization';
5
5
  export * from './TMIcons';
6
6
  export * from './TMImageLibrary';
7
7
  export * from './helpers';
8
+ export * from './dataGridSearchHelper';
8
9
  export * from './queryHelper';
9
10
  export * from './TMUtils';
10
11
  export * from './TMCommandsContextMenu';
@@ -5,6 +5,7 @@ export * from './Globalization';
5
5
  export * from './TMIcons';
6
6
  export * from './TMImageLibrary';
7
7
  export * from './helpers';
8
+ export * from './dataGridSearchHelper';
8
9
  export * from './queryHelper';
9
10
  export * from './TMUtils';
10
11
  export * from './TMCommandsContextMenu';
@@ -14,6 +14,8 @@ export declare function addWhereClausesForConnect(qd: QueryDescriptor): void;
14
14
  export declare function getDefaultOperator(dataDomain: MetadataDataDomains | undefined, dataType: MetadataDataTypes | undefined): QueryOperators.Equal | QueryOperators.Contain | QueryOperators.In;
15
15
  export declare const getQD: (tid: number | undefined, easyOr: boolean, newMaxDcmtsToBeReturned: number) => Promise<QueryDescriptor | undefined>;
16
16
  export declare const getWorkItemSetIDAsync: (vid: number, did: number) => Promise<string | undefined>;
17
+ /** Id assegnato alla ricerca di sistema con tutti i documenti: non è in cache, va ricostruita a runtime con getSysAllDcmtsSQD */
18
+ export declare const SYS_ALL_DCMTS_SQD_ID = 1;
17
19
  export declare const getSysAllDcmtsSQD: (tid: number | undefined, easyOr: boolean) => Promise<SavedQueryDescriptor>;
18
20
  export declare const searchResultToMetadataValues: (tid: number | undefined, dtd: DataTableDescriptor | undefined, rows: string[], mids: number[], metadata: MetadataDescriptor[], layoutMode: LayoutModes, isReadOnlyOrigin?: boolean) => MetadataValueDescriptorEx[];
19
21
  export declare const handleArchiveVisibility: (md: MetadataDescriptor) => boolean;