@sapui5/sap.fe.macros 1.142.0 → 1.143.0

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 (102) hide show
  1. package/package.json +1 -1
  2. package/src/sap/fe/macros/.library +1 -1
  3. package/src/sap/fe/macros/CollaborativeDraftHandler.js +1 -7
  4. package/src/sap/fe/macros/CollaborativeDraftHandler.tsx +0 -6
  5. package/src/sap/fe/macros/ConditionalSwitch.js +1 -2
  6. package/src/sap/fe/macros/ConditionalSwitch.tsx +0 -1
  7. package/src/sap/fe/macros/ConditionalSwitchProperty.js +1 -3
  8. package/src/sap/fe/macros/ConditionalSwitchProperty.tsx +0 -2
  9. package/src/sap/fe/macros/Field.js +5 -5
  10. package/src/sap/fe/macros/Field.ts +5 -3
  11. package/src/sap/fe/macros/FooterContent.js +3 -2
  12. package/src/sap/fe/macros/FooterContent.tsx +2 -10
  13. package/src/sap/fe/macros/KPITag.js +6 -6
  14. package/src/sap/fe/macros/KPITag.tsx +5 -5
  15. package/src/sap/fe/macros/MacroAPI.js +2 -2
  16. package/src/sap/fe/macros/MacroAPI.ts +1 -1
  17. package/src/sap/fe/macros/MessageButton.js +3 -3
  18. package/src/sap/fe/macros/MessageButton.tsx +3 -2
  19. package/src/sap/fe/macros/MicroChart.js +3 -2
  20. package/src/sap/fe/macros/MicroChart.tsx +1 -1
  21. package/src/sap/fe/macros/Share.js +7 -7
  22. package/src/sap/fe/macros/Share.tsx +9 -6
  23. package/src/sap/fe/macros/Status.js +6 -5
  24. package/src/sap/fe/macros/Status.tsx +3 -4
  25. package/src/sap/fe/macros/ai/EasyFillDialog.js +2 -1
  26. package/src/sap/fe/macros/ai/EasyFillDialog.tsx +1 -0
  27. package/src/sap/fe/macros/ai/SummarizationButton.js +6 -4
  28. package/src/sap/fe/macros/ai/SummarizationButton.tsx +5 -3
  29. package/src/sap/fe/macros/chart/ChartDelegate.js +22 -1
  30. package/src/sap/fe/macros/chart/ChartDelegate.ts +29 -2
  31. package/src/sap/fe/macros/chart/MdcChartTemplate.js +5 -2
  32. package/src/sap/fe/macros/chart/MdcChartTemplate.tsx +5 -2
  33. package/src/sap/fe/macros/controls/BuildingBlockObjectProperty.js +7 -7
  34. package/src/sap/fe/macros/controls/BuildingBlockObjectProperty.ts +3 -2
  35. package/src/sap/fe/macros/controls/FileWrapper.js +11 -5
  36. package/src/sap/fe/macros/controls/FileWrapper.ts +10 -4
  37. package/src/sap/fe/macros/controls/NumberWithUnitOrCurrency.js +3 -1
  38. package/src/sap/fe/macros/controls/NumberWithUnitOrCurrency.tsx +2 -0
  39. package/src/sap/fe/macros/coreUI/CreateDialog.js +2 -2
  40. package/src/sap/fe/macros/coreUI/CreateDialog.tsx +1 -1
  41. package/src/sap/fe/macros/coreUI/OperationParameterDialog.js +4 -4
  42. package/src/sap/fe/macros/coreUI/OperationParameterDialog.tsx +3 -3
  43. package/src/sap/fe/macros/field/FieldFormatOptions.js +2 -2
  44. package/src/sap/fe/macros/field/FieldFormatOptions.ts +1 -1
  45. package/src/sap/fe/macros/field/FieldRuntime.js +7 -2
  46. package/src/sap/fe/macros/field/FieldRuntime.ts +7 -1
  47. package/src/sap/fe/macros/filter/FilterUtils.js +31 -5
  48. package/src/sap/fe/macros/filter/FilterUtils.ts +40 -6
  49. package/src/sap/fe/macros/filterBar/FilterBarAPI.js +6 -3
  50. package/src/sap/fe/macros/filterBar/FilterBarAPI.ts +5 -1
  51. package/src/sap/fe/macros/filterBar/FilterBarDelegate.js +19 -9
  52. package/src/sap/fe/macros/filterBar/FilterBarDelegate.ts +76 -61
  53. package/src/sap/fe/macros/filterBar/UOMValidationDelegate.js +376 -0
  54. package/src/sap/fe/macros/filterBar/UOMValidationDelegate.ts +463 -0
  55. package/src/sap/fe/macros/form/FormContainer.block.js +22 -6
  56. package/src/sap/fe/macros/form/FormContainer.block.ts +24 -6
  57. package/src/sap/fe/macros/internal/valuehelp/ValueListHelper.js +2 -2
  58. package/src/sap/fe/macros/internal/valuehelp/ValueListHelper.ts +2 -1
  59. package/src/sap/fe/macros/library.js +5 -6
  60. package/src/sap/fe/macros/{library.ts → library.tsx} +1 -1
  61. package/src/sap/fe/macros/messagebundle.properties +6 -0
  62. package/src/sap/fe/macros/messagebundle_en_US_saprigi.properties +1 -1
  63. package/src/sap/fe/macros/messages/MessageButton.js +21 -12
  64. package/src/sap/fe/macros/messages/MessageButton.ts +21 -11
  65. package/src/sap/fe/macros/multivaluefield/MultiValueFieldDelegate.js +7 -3
  66. package/src/sap/fe/macros/multivaluefield/MultiValueFieldDelegate.ts +8 -2
  67. package/src/sap/fe/macros/quickView/QuickView.js +5 -4
  68. package/src/sap/fe/macros/quickView/QuickView.tsx +10 -3
  69. package/src/sap/fe/macros/table/Action.js +7 -4
  70. package/src/sap/fe/macros/table/Action.ts +3 -3
  71. package/src/sap/fe/macros/table/Column.js +3 -2
  72. package/src/sap/fe/macros/table/Column.ts +1 -1
  73. package/src/sap/fe/macros/table/MdcTableTemplate.js +6 -9
  74. package/src/sap/fe/macros/table/MdcTableTemplate.tsx +5 -7
  75. package/src/sap/fe/macros/table/Table.block.js +6 -3
  76. package/src/sap/fe/macros/table/Table.block.tsx +13 -3
  77. package/src/sap/fe/macros/table/TableAPI.js +13 -8
  78. package/src/sap/fe/macros/table/TableAPI.ts +10 -3
  79. package/src/sap/fe/macros/table/TableDefinition.js +2 -2
  80. package/src/sap/fe/macros/table/TableDefinition.ts +1 -1
  81. package/src/sap/fe/macros/table/TableEventHandlerProvider.js +3 -1
  82. package/src/sap/fe/macros/table/TableEventHandlerProvider.ts +4 -0
  83. package/src/sap/fe/macros/table/TableRuntime.js +24 -12
  84. package/src/sap/fe/macros/table/TableRuntime.ts +27 -11
  85. package/src/sap/fe/macros/table/Utils.js +9 -3
  86. package/src/sap/fe/macros/table/Utils.ts +14 -8
  87. package/src/sap/fe/macros/table/delegates/TableDelegate.js +6 -4
  88. package/src/sap/fe/macros/table/delegates/TableDelegate.ts +6 -5
  89. package/src/sap/fe/macros/table/massEdit/MassEditDialog.js +41 -15
  90. package/src/sap/fe/macros/table/massEdit/MassEditDialog.tsx +41 -22
  91. package/src/sap/fe/macros/table/massEdit/MassEditDialogHelper.js +14 -5
  92. package/src/sap/fe/macros/table/massEdit/MassEditDialogHelper.tsx +13 -4
  93. package/src/sap/fe/macros/table/mixin/ContextMenuHandler.js +2 -3
  94. package/src/sap/fe/macros/table/mixin/ContextMenuHandler.ts +3 -2
  95. package/src/sap/fe/macros/table/mixin/EmptyRowsHandler.js +37 -10
  96. package/src/sap/fe/macros/table/mixin/EmptyRowsHandler.ts +39 -15
  97. package/src/sap/fe/macros/table/mixin/TableHierarchy.js +3 -4
  98. package/src/sap/fe/macros/table/mixin/TableHierarchy.ts +2 -3
  99. package/src/sap/fe/macros/table/uploadTable/UploadTableRuntime.js +5 -4
  100. package/src/sap/fe/macros/table/uploadTable/UploadTableRuntime.ts +6 -3
  101. package/src/sap/fe/macros/valuehelp/ValueHelpDelegate.js +17 -10
  102. package/src/sap/fe/macros/valuehelp/ValueHelpDelegate.ts +24 -9
@@ -0,0 +1,463 @@
1
+ /**
2
+ * UOMValidationDelegate
3
+ *
4
+ * A FilterBarDelegate extension that adds UOM validation behavior to MDC FilterBars including adaptation and personalization variants used in the Table and Chart or FilterBar P13n.
5
+ *
6
+ * The delegate inspects filter fields for an associated Measures or ISOCurrency or Unit annotation and enforces
7
+ * when a value is entered for the leading (measure) field, a corresponding UOM value
8
+ * either exists or is requested from the user. It updates the FilterField value states and required
9
+ * flags, manages message suppression for live searches, and can reorder the visible UOM field next to
10
+ * its leading field in personalization state when required.
11
+ *
12
+ * Key behaviors:
13
+ * - Works with three FilterBar contexts:
14
+ * - Main (normal) FilterBar
15
+ * - FilterBar P13n (adaptation UI for FilterBar)
16
+ * - Table or Chart P13n (adaptation UI for Table or Chart FilterBar)
17
+ * - Discovers UOM relationships using the converted filter field metadata and the Measures.ISOCurrency or Measures.Unit
18
+ * annotation on the corresponding property.
19
+ * - Determines the validation trigger by inspecting the FilterBar "reason" such as Enter or Go and live mode.
20
+ * - Sets the value state and value state text on the leading (measure) field and marks the UOM FilterField
21
+ * as required when the leading field has a value but no UOM.
22
+ * - Resets value states when no relevant conditions are present.
23
+ *
24
+ * Usage:
25
+ * - The delegate exposes determineValidationState(filterBar, validationType) which returns a Promise
26
+ * resolving to a FilterBarValidationStatus. This method is intended to be invoked by the FilterBar
27
+ * validation lifecycle to decide whether a search should be triggered or whether missing values
28
+ * should be presented to the user.
29
+ */
30
+ import type { Property, PropertyPath } from "@sap-ux/vocabularies-types";
31
+ import CommonUtils from "sap/fe/core/CommonUtils";
32
+ import type ResourceModel from "sap/fe/core/ResourceModel";
33
+ import type { FilterField } from "sap/fe/core/converters/controls/ListReport/FilterBar";
34
+ import * as ResourceModelHelper from "sap/fe/core/helpers/ResourceModelHelper";
35
+ import type Control from "sap/ui/core/Control";
36
+ import UI5Element from "sap/ui/core/Element";
37
+ import Messaging from "sap/ui/core/Messaging";
38
+ import ControlMessageProcessor from "sap/ui/core/message/ControlMessageProcessor";
39
+ import Message from "sap/ui/core/message/Message";
40
+ import MessageType from "sap/ui/core/message/MessageType";
41
+ import type Chart from "sap/ui/mdc/Chart";
42
+ import type FilterBar from "sap/ui/mdc/FilterBar";
43
+ import type MDCFilterField from "sap/ui/mdc/FilterField";
44
+ import type Table from "sap/ui/mdc/Table";
45
+ import FilterBarValidationStatus from "sap/ui/mdc/enums/FilterBarValidationStatus";
46
+ import type JSONModel from "sap/ui/model/json/JSONModel";
47
+ import type ODataMetaModel from "sap/ui/model/odata/v4/ODataMetaModel";
48
+ import DelegateUtil from "../DelegateUtil";
49
+ import type { IFilterControl } from "../filter/FilterUtils";
50
+ import FilterUtils from "../filter/FilterUtils";
51
+
52
+ // Type alias representing possible adaptation control element types (FilterBar | Table | Chart)
53
+ type AdaptationElement = FilterBar | Table | Chart;
54
+
55
+ const UOMValidationDelegate = {
56
+ /**
57
+ * Function which determines the validation state of the FilterFields on a given FilterBar control.
58
+ * @param filterBar FilterBar control which can be a P13n FilterBar or a regular one
59
+ * @param _mValidation String which consists which type of validation is happening
60
+ * @returns A Promise with a Validation Status which determines if the search is triggered or not
61
+ */
62
+ determineValidationState: async function (filterBar: FilterBar, _mValidation: string): Promise<FilterBarValidationStatus> {
63
+ const adaptationControlElement = UI5Element.getElementById(filterBar.getAssociation("adaptationControl", null) as string);
64
+ const filterType = getFilterBarType(filterBar, adaptationControlElement as AdaptationElement);
65
+ const { hasError, hasWarning } = await UOMValidationDelegate.validateAllUOMFields(
66
+ filterBar,
67
+ filterBar._sReason,
68
+ filterType,
69
+ adaptationControlElement
70
+ );
71
+ if (!hasError && !hasWarning) {
72
+ return new Promise((resolve) => {
73
+ //After discussions with MDC we need to use this as a temporary workaround to solve the timing issues related to setting the messages to the filterfield and update of the filterfield valuestate
74
+ //TODO: Remove this workaround once MDC provides an API to set the messages to the filterbar. Will be tracked via BLI.
75
+ setTimeout(() => {
76
+ resolve(filterBar.checkFilters());
77
+ }, 0);
78
+ });
79
+ }
80
+ //if warning or liveMode, we don't open message box
81
+ filterBar.setShowMessages(!hasWarning && !filterBar.getLiveMode());
82
+ return hasError ? FilterBarValidationStatus.FieldInErrorState : filterBar.checkFilters();
83
+ },
84
+ validateAllUOMFields: async function (
85
+ filterBar: FilterBar,
86
+ reason?: string,
87
+ filterType?: FilterType,
88
+ adaptationControlElement?: UI5Element
89
+ ): Promise<{ hasError: boolean; hasWarning: boolean }> {
90
+ let hasError = false,
91
+ hasWarning = false;
92
+ let entityTypePath: string | undefined;
93
+ let controlForMetaModel: UI5Element | undefined;
94
+ adaptationControlElement =
95
+ adaptationControlElement ?? UI5Element.getElementById(filterBar.getAssociation("adaptationControl", null) as string);
96
+ filterType = filterType ?? getFilterBarType(filterBar, adaptationControlElement as AdaptationElement);
97
+ if (filterType === FilterType.FILTERBAR_P13N || filterType === FilterType.TABLE_CHART_P13N) {
98
+ entityTypePath = DelegateUtil.getCustomData<string>(adaptationControlElement as FilterBar, "entityType") as string;
99
+ controlForMetaModel = adaptationControlElement;
100
+ } else {
101
+ entityTypePath = DelegateUtil.getCustomData<string>(filterBar, "entityType") as string;
102
+ controlForMetaModel = filterBar;
103
+ }
104
+ const view = CommonUtils.getTargetView(controlForMetaModel as Control);
105
+ const appComponent = view && CommonUtils.getAppComponent(view);
106
+ const disableStrictUomFiltering = appComponent?.getManifestEntry("sap.fe")?.app?.disableStrictUomFiltering;
107
+ if (disableStrictUomFiltering === true) {
108
+ return { hasError: false, hasWarning: false };
109
+ }
110
+
111
+ const internalModel = controlForMetaModel?.getModel("internal");
112
+ const filterBarId = filterBar.getId();
113
+ const allUomValidationMessages = internalModel?.getProperty("/uomValidationMessages") || {};
114
+ const filterBarUomValidationMessages = allUomValidationMessages[filterBarId] || {};
115
+
116
+ // Clear existing UOM validation messages for this filterBar from the message model
117
+ removeMessages(internalModel as JSONModel, filterBarId, filterBarUomValidationMessages);
118
+ const model = await DelegateUtil.fetchModel(controlForMetaModel as AdaptationElement);
119
+ const metaModel = model?.getMetaModel() as ODataMetaModel;
120
+ const resourceModel = ResourceModelHelper.getResourceModel(controlForMetaModel as Control);
121
+ const allUOMProperties = getUOMProperties(entityTypePath, filterBar as IFilterControl, metaModel);
122
+ if (
123
+ !allUOMProperties.length ||
124
+ !allUOMProperties.some((uomProp: UOMProperty) => filterBar?.getConditions()?.[uomProp?.field?.fieldKey]?.length > 0)
125
+ ) {
126
+ uomStateMap = {};
127
+ return { hasError: false, hasWarning: false };
128
+ }
129
+ for (const { field, uomProperty } of allUOMProperties) {
130
+ if (uomProperty) {
131
+ const { hasError: fieldHasError, hasWarning: fieldHasWarning } = validateFilterField(
132
+ filterBar,
133
+ field,
134
+ uomProperty,
135
+ filterType,
136
+ resourceModel,
137
+ adaptationControlElement,
138
+ reason as string,
139
+ internalModel as JSONModel
140
+ );
141
+
142
+ if (fieldHasError) hasError = true;
143
+ if (fieldHasWarning) hasWarning = true;
144
+ }
145
+ }
146
+ uomStateMap = {};
147
+ return { hasError, hasWarning };
148
+ }
149
+ };
150
+ /**
151
+ * Interface representing a unit of measure (UOM) property and its associated field.
152
+ * Used to track relationships between measure fields and their corresponding UOM fields.
153
+ * @interface
154
+ */
155
+ interface UOMProperty {
156
+ /**
157
+ * The main measure field information
158
+ */
159
+ field: {
160
+ /** Unique identifier for the field */
161
+ fieldKey: string;
162
+ /** Display label for the field */
163
+ label: string;
164
+ };
165
+ /**
166
+ * Optional associated unit of measure (UOM) field information
167
+ */
168
+ uomProperty?: {
169
+ /** Path to the UOM field */
170
+ path: string;
171
+ /** Display label for the UOM field */
172
+ label: string;
173
+ };
174
+ }
175
+
176
+ /**
177
+ * Enumeration of possible FilterBar types in the application.
178
+ * Used to determine the validation behavior based on the context where the filter is being used.
179
+ * @enum {string}
180
+ */
181
+ enum FilterType {
182
+ /** Regular FilterBar instance (not in personalization mode) */
183
+ MAIN = "Main",
184
+ /** FilterBar in personalization mode for filter adaptation */
185
+ FILTERBAR_P13N = "FilterP13n",
186
+ /** FilterBar in personalization mode for Table or Chart adaptation */
187
+ TABLE_CHART_P13N = "TableChartP13n"
188
+ }
189
+
190
+ let uomStateMap: Record<string, { messageType?: MessageType }> = {};
191
+ let controlMessageProcessor: ControlMessageProcessor | undefined;
192
+ /**
193
+ * Determines the FilterType for a given FilterBar and an optional adaptation control element.
194
+ *
195
+ * The function classifies the filter bar into one of three FilterType values:
196
+ * - FilterType.MAIN: When the provided filterBar is not an adaptation such when it is not an AdaptationFilterBar.
197
+ * - FilterType.FILTERBAR_P13N: When the provided filterBar is an AdaptationFilterBar but the adaptationControlElement
198
+ * is not a Table or Chart.
199
+ * - FilterType.TABLE_CHART_P13N: When the provided filterBar is an AdaptationFilterBar and the
200
+ * adaptationControlElement is a Table or Chart.
201
+ * @param filterBar The FilterBar instance to inspect. Expected to implement isA().
202
+ * @param adaptationControlElement The control associated with the adaptation workflow which may be a FilterBar, Table, or Chart. Used to distinguish table or chart personalization from general filter bar personalization.
203
+ * @returns The resolved FilterType enum value representing how the filter bar should be treated.
204
+ */
205
+ function getFilterBarType(filterBar: FilterBar, adaptationControlElement: FilterBar | Table | Chart): FilterType {
206
+ if (filterBar.isA("sap.ui.mdc.filterbar.p13n.AdaptationFilterBar")) {
207
+ if ((adaptationControlElement as Table)?.isA("sap.ui.mdc.Table") || (adaptationControlElement as Chart)?.isA("sap.ui.mdc.Chart")) {
208
+ return FilterType.TABLE_CHART_P13N;
209
+ }
210
+ return FilterType.FILTERBAR_P13N;
211
+ }
212
+ return FilterType.MAIN;
213
+ }
214
+
215
+ /**
216
+ * Determines whether an error state check should be performed based on the triggering reason,
217
+ * the type of filter context, and the filter bar's configuration.
218
+ *
219
+ * The function returns true for explicit user actions (for example, "Enter", "Go", or "Variant"),
220
+ * when the filter bar is of the table or chart personalization type, or when the filter bar
221
+ * personalization is active and the filter bar is in live mode.
222
+ * @param reason A string describing the event or user action that triggered validation. For example, "Enter", "Go", or "Variant".
223
+ * @param filterType The FilterType enum value indicating the current filter context which is used to detect personalization contexts.
224
+ * @param filterBar Optional FilterBar instance. When provided, its live mode is consulted for certain personalization types.
225
+ * @returns True if an error state should be checked given the inputs. Otherwise, false.
226
+ */
227
+ function shouldCheckErrorState(reason: string, filterType: FilterType, filterBar: FilterBar | undefined): boolean {
228
+ return (
229
+ reason === "Enter" ||
230
+ reason === "Go" ||
231
+ reason === "Variant" ||
232
+ (filterBar?.getLiveMode() as boolean) ||
233
+ filterType === FilterType.TABLE_CHART_P13N
234
+ );
235
+ }
236
+
237
+ /**
238
+ * Removes existing UOM validation messages for a specific filterBar from the message model
239
+ * and clears the uomValidationMessages property in the internal model.
240
+ * @param internalModel The internal JSONModel containing the validation messages
241
+ * @param filterBarId The ID of the filterBar whose messages should be removed
242
+ * @param filterBarUomValidationMessages The current UOM validation messages for this filterBar
243
+ */
244
+ function removeMessages(
245
+ internalModel: JSONModel | undefined,
246
+ filterBarId: string,
247
+ filterBarUomValidationMessages: Record<string, string>
248
+ ): void {
249
+ if (Object.keys(filterBarUomValidationMessages).length > 0) {
250
+ const allMessages: Message[] = Messaging.getMessageModel().getData();
251
+ const messagesToRemove = allMessages.filter((m) => Object.values(filterBarUomValidationMessages).includes(m.getId()));
252
+ if (messagesToRemove.length) {
253
+ Messaging.removeMessages(messagesToRemove);
254
+ }
255
+ // Clear the uomValidationMessages property for this specific filterBar
256
+ if (internalModel) {
257
+ const allUomValidationMessages = internalModel.getProperty("/uomValidationMessages") || {};
258
+ const updatedMessages = { ...allUomValidationMessages };
259
+ delete updatedMessages[filterBarId];
260
+ internalModel.setProperty("/uomValidationMessages", updatedMessages);
261
+ }
262
+ }
263
+ }
264
+
265
+ /**
266
+ * Function to validate the fields.
267
+ * @param filterBar The control on which the fields exist and whose ID will be used as message storage key
268
+ * @param field The field to be evaluated which has a fieldKey and label
269
+ * @param field.fieldKey
270
+ * @param field.label
271
+ * @param uomProperty The UOM property if any exists for the field
272
+ * @param uomProperty.path
273
+ * @param uomProperty.label
274
+ * @param filterType The type of the filterBar
275
+ * @param resourceModel
276
+ * @param adaptationControlElement
277
+ * @param reason
278
+ * @param internalModel The internal JSONModel for message storage
279
+ * @returns An object consisting of whether we have an error or a warning state
280
+ */
281
+ function validateFilterField(
282
+ filterBar: FilterBar,
283
+ field: { fieldKey: string; label: string },
284
+ uomProperty: { path: string; label: string },
285
+ filterType: FilterType,
286
+ resourceModel: ResourceModel,
287
+ adaptationControlElement: UI5Element | undefined,
288
+ reason: string,
289
+ internalModel?: JSONModel
290
+ ): { hasError: boolean; hasWarning: boolean } {
291
+ const { fieldKey, label } = field;
292
+ const associatedUOMPropertyPath = uomProperty.path;
293
+ const filterBarConditions = filterBar.getConditions();
294
+ const isFieldNameInConditions = !!filterBarConditions?.[fieldKey]?.length;
295
+ const isUOMInConditions = associatedUOMPropertyPath ? filterBarConditions?.[associatedUOMPropertyPath]?.length === 1 : false;
296
+ const doesUOMHaveMultipleConditions = associatedUOMPropertyPath ? filterBarConditions?.[associatedUOMPropertyPath]?.length > 1 : false;
297
+ const leadingFilterField = filterBar.getFilterItems().find((item) => item.getPropertyKey() === fieldKey);
298
+ const uomFilterField = filterBar.getFilterItems().find((item) => item.getPropertyKey() === associatedUOMPropertyPath);
299
+ const messageText = doesUOMHaveMultipleConditions
300
+ ? resourceModel?.getText?.("FILTERFIELD_VALUE_UOM_MULTIPLE", [uomFilterField?.getLabel() ?? uomProperty?.label])
301
+ : resourceModel?.getText?.("FILTERFIELD_VALUE_NO_UOM", [
302
+ leadingFilterField?.getLabel() ?? label,
303
+ uomFilterField?.getLabel() ?? uomProperty?.label
304
+ ]);
305
+ if (!isFieldNameInConditions || (isFieldNameInConditions && isUOMInConditions)) {
306
+ return { hasError: false, hasWarning: false };
307
+ }
308
+
309
+ const isError = shouldCheckErrorState(
310
+ reason,
311
+ filterType,
312
+ filterType === FilterType.FILTERBAR_P13N ? (adaptationControlElement as FilterBar) : filterBar
313
+ );
314
+ setMessages(
315
+ leadingFilterField,
316
+ uomFilterField,
317
+ isError ? MessageType.Error : MessageType.Warning,
318
+ messageText,
319
+ internalModel as JSONModel,
320
+ filterBar
321
+ );
322
+ return { hasError: isError, hasWarning: !isError };
323
+ }
324
+
325
+ /**
326
+ * Updates the UI state for a leading filter field and its associated UOM filter field.
327
+ * Sets the ValueState and optional ValueStateText on the leading filter (if present),
328
+ * and sets the required flag as well as ValueState and ValueStateText on the UOM filter (if present).
329
+ * @param leadingFilterField The primary (leading) MDCFilterField to update. Only its value state and text are modified.
330
+ * @param uomFilterField The UOM MDCFilterField to update. Its required flag, value state, and text are modified.
331
+ * @param messageType The ValueState to apply such as None, Warning, Error, or Success.
332
+ * @param message Optional descriptive text to display for the value state.
333
+ * @param internalModel The internal JSONModel for message storage.
334
+ * @param filterBar The FilterBar whose ID will be used as the key for message storage in the internal model.
335
+ */
336
+ function setMessages(
337
+ leadingFilterField: MDCFilterField | undefined,
338
+ uomFilterField: MDCFilterField | undefined,
339
+ messageType: MessageType,
340
+ message: string | undefined,
341
+ internalModel?: JSONModel,
342
+ filterBar?: FilterBar
343
+ ): void {
344
+ const messages: Message | Message[] = [];
345
+ controlMessageProcessor ??= new ControlMessageProcessor();
346
+
347
+ // Get current UOM validation messages from internal model
348
+ const filterBarId = filterBar?.getId() ?? "";
349
+ const allUomValidationMessages = internalModel?.getProperty("/uomValidationMessages") || {};
350
+ const filterBarUomValidationMessages: Record<string, string> = allUomValidationMessages[filterBarId] || {};
351
+
352
+ let leadingMsg: Message | undefined;
353
+ if (leadingFilterField) {
354
+ const fieldId = leadingFilterField.getId();
355
+ // Check if message already exists for this field in this filterBar's context
356
+ if (!filterBarUomValidationMessages[fieldId]) {
357
+ leadingMsg = new Message({
358
+ message: message,
359
+ processor: controlMessageProcessor,
360
+ type: messageType,
361
+ target: fieldId + "/conditions"
362
+ });
363
+ messages.push(leadingMsg);
364
+ // Store message ID in filterBar's validation messages
365
+ filterBarUomValidationMessages[fieldId] = leadingMsg.getId();
366
+ }
367
+ }
368
+ if (uomFilterField && uomStateMap[uomFilterField.getId()] !== undefined) {
369
+ if (uomStateMap[uomFilterField.getId()]?.messageType === MessageType.None) {
370
+ setMessageForUOMField(uomFilterField, messageType, message, messages, filterBarUomValidationMessages);
371
+ }
372
+ } else if (uomFilterField) {
373
+ setMessageForUOMField(uomFilterField, messageType, message, messages, filterBarUomValidationMessages);
374
+ }
375
+
376
+ // Update internal model with new messages for this filterBar
377
+ if (internalModel) {
378
+ const updatedAllMessages = { ...allUomValidationMessages };
379
+ updatedAllMessages[filterBarId] = filterBarUomValidationMessages;
380
+ internalModel.setProperty("/uomValidationMessages", updatedAllMessages);
381
+ }
382
+ if (messages.length) {
383
+ Messaging.addMessages(messages);
384
+ }
385
+ }
386
+
387
+ function setMessageForUOMField(
388
+ uomField: MDCFilterField,
389
+ messageType: MessageType,
390
+ message: string | undefined,
391
+ messages: Message[],
392
+ uomValidationMessages: Record<string, string>
393
+ ): Message | undefined {
394
+ const fieldId = uomField.getId();
395
+ // Check if message already exists for this field
396
+ if (uomValidationMessages[fieldId]) {
397
+ return undefined;
398
+ }
399
+ const msg = new Message({
400
+ message: message,
401
+ processor: controlMessageProcessor,
402
+ type: messageType,
403
+ target: fieldId + "/conditions"
404
+ });
405
+ messages.push(msg);
406
+ uomStateMap[fieldId] = { messageType };
407
+
408
+ // Store message ID in uomValidationMessages
409
+ uomValidationMessages[fieldId] = msg.getId();
410
+ return msg;
411
+ }
412
+
413
+ /**
414
+ * Retrieves UOM-related properties from a filter control's metadata.
415
+ * Processes filter fields to identify measure fields with associated UOM fields
416
+ * through ISOCurrency or Unit annotations.
417
+ * @param entityTypePath Path to the entity type containing the filter fields
418
+ * @param filterControl The filter control to inspect for UOM properties
419
+ * @param metaModel ODataMetaModel
420
+ * @returns Array of UOMProperty objects containing measure field information
421
+ * and their associated UOM field details
422
+ */
423
+ function getUOMProperties(
424
+ entityTypePath: string | undefined,
425
+ filterControl: IFilterControl,
426
+ metaModel?: ODataMetaModel | undefined
427
+ ): UOMProperty[] {
428
+ const includeHidden = filterControl.isA("sap.ui.mdc.filterbar.vh.FilterBar") ? true : undefined;
429
+ const filterFields = FilterUtils.getConvertedFilterFields(filterControl, entityTypePath, includeHidden, metaModel);
430
+ const converterContext = FilterUtils.createConverterContext(filterControl, entityTypePath, metaModel);
431
+ return filterFields
432
+ .map((filterFieldInfo: FilterField) => {
433
+ const annotationPath = filterFieldInfo.annotationPath;
434
+ if (annotationPath) {
435
+ const propertyAnnotations = converterContext.getConvertedTypes().resolvePath<Property>(annotationPath).target;
436
+ const uomProperty = propertyAnnotations?.annotations.Measures;
437
+ if (uomProperty?.ISOCurrency || uomProperty?.Unit) {
438
+ let uomPropertyObject;
439
+ const uomPath =
440
+ (uomProperty as { ISOCurrency?: { path: string } })?.ISOCurrency?.path ||
441
+ (uomProperty as { Unit?: { path: string } })?.Unit?.path;
442
+ if (uomPath) {
443
+ const uomLabel = filterFields.find((ff) => ff.key === uomPath)?.label;
444
+ uomPropertyObject = {
445
+ path: uomPath,
446
+ label:
447
+ uomLabel ??
448
+ (uomProperty?.ISOCurrency as unknown as PropertyPath)?.$target?.annotations?.Common?.Label ??
449
+ (uomProperty?.Unit as unknown as PropertyPath)?.$target?.annotations?.Common?.Label
450
+ };
451
+ }
452
+ return {
453
+ field: { fieldKey: filterFieldInfo.key ?? "", label: filterFieldInfo.label ?? "" },
454
+ uomProperty: uomPropertyObject
455
+ };
456
+ }
457
+ }
458
+ return null;
459
+ })
460
+ .filter(Boolean) as UOMProperty[];
461
+ }
462
+
463
+ export default UOMValidationDelegate;