@gooddata/sdk-ui-dashboard 11.36.0-alpha.3 → 11.36.0-alpha.7

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 (173) hide show
  1. package/NOTICE +74 -162
  2. package/esm/__version.d.ts +1 -1
  3. package/esm/__version.js +1 -1
  4. package/esm/index.d.ts +5 -13
  5. package/esm/index.js +2 -10
  6. package/esm/internal.d.ts +1 -1
  7. package/esm/model/commandHandlers/dashboard/common/filterViews.js +24 -1
  8. package/esm/model/commandHandlers/dashboard/common/parameterHydration.d.ts +7 -1
  9. package/esm/model/commandHandlers/dashboard/common/parameterHydration.js +16 -2
  10. package/esm/model/commandHandlers/dashboard/common/stateInitializers.js +4 -2
  11. package/esm/model/commandHandlers/drill/resolveDrillToCustomUrl.d.ts +7 -1
  12. package/esm/model/commandHandlers/drill/resolveDrillToCustomUrl.js +80 -4
  13. package/esm/model/commandHandlers/filterContext/filterViewHandler.js +10 -0
  14. package/esm/model/commandHandlers/filterContext/filterViewParameters.d.ts +7 -0
  15. package/esm/model/commandHandlers/filterContext/filterViewParameters.js +11 -0
  16. package/esm/model/store/config/configSelectors.d.ts +0 -12
  17. package/esm/model/store/config/configSelectors.js +2 -18
  18. package/esm/model/store/tabs/index.d.ts +4 -0
  19. package/esm/model/store/tabs/parameters/parametersReducers.d.ts +11 -1
  20. package/esm/model/store/tabs/parameters/parametersReducers.js +16 -8
  21. package/esm/model/store/tabs/parameters/parametersSelectors.d.ts +7 -0
  22. package/esm/model/store/tabs/parameters/parametersSelectors.js +17 -0
  23. package/esm/model/store/widgetDrills/widgetDrillSelectors.js +10 -18
  24. package/esm/model/types/commonTypes.d.ts +11 -2
  25. package/esm/model/utils/measureValueFilterUtils.d.ts +14 -0
  26. package/esm/model/utils/measureValueFilterUtils.js +21 -0
  27. package/esm/presentation/alerting/DefaultAlertingDialog/{DefaultAlertingDialogNew.d.ts → DefaultAlertingDialog.d.ts} +1 -1
  28. package/esm/presentation/alerting/DefaultAlertingDialog/{DefaultAlertingDialogNew.js → DefaultAlertingDialog.js} +6 -12
  29. package/esm/presentation/alerting/DefaultAlertingDialog/components/AlertAttributeSelect.js +43 -9
  30. package/esm/presentation/alerting/DefaultAlertingDialog/hooks/useSaveAlertToBackend.js +13 -25
  31. package/esm/presentation/alerting/DefaultAlertingDialog/utils/items.js +5 -2
  32. package/esm/presentation/alerting/types.d.ts +1 -72
  33. package/esm/presentation/automationFilters/hooks/useValidateExistingAutomationFilters.d.ts +1 -2
  34. package/esm/presentation/automationFilters/hooks/useValidateExistingAutomationFilters.js +5 -5
  35. package/esm/presentation/dashboard/DashboardHeader/AlertingDialogProvider.js +1 -8
  36. package/esm/presentation/dashboard/DashboardHeader/ScheduledEmailDialogProvider.js +17 -8
  37. package/esm/presentation/dashboard/DashboardHeader/ShareDialogDashboardHeader.js +5 -2
  38. package/esm/presentation/dashboard/components/DashboardRenderer.js +2 -2
  39. package/esm/presentation/drill/DrillConfigPanel/DrillToUrl/CustomUrlEditor.js +97 -13
  40. package/esm/presentation/drill/DrillConfigPanel/DrillToUrl/CustomUrlEditorParameters.d.ts +1 -1
  41. package/esm/presentation/drill/DrillConfigPanel/DrillToUrl/CustomUrlEditorParameters.js +3 -3
  42. package/esm/presentation/drill/DrillConfigPanel/DrillToUrl/CustomUrlEditorParametersSections/DashboardParametersSection.d.ts +3 -2
  43. package/esm/presentation/drill/DrillConfigPanel/DrillToUrl/CustomUrlEditorParametersSections/DashboardParametersSection.js +17 -4
  44. package/esm/presentation/drill/DrillConfigPanel/DrillToUrl/CustomUrlEditorParametersSections/InsightParametersSection.d.ts +4 -2
  45. package/esm/presentation/drill/DrillConfigPanel/DrillToUrl/CustomUrlEditorParametersSections/InsightParametersSection.js +37 -4
  46. package/esm/presentation/drill/DrillConfigPanel/DrillToUrl/CustomUrlEditorParametersSections/Parameter.d.ts +4 -3
  47. package/esm/presentation/drill/DrillConfigPanel/DrillToUrl/CustomUrlEditorParametersSections/Parameter.js +3 -4
  48. package/esm/presentation/drill/DrillSelect/DrillSelectDropdown.js +1 -3
  49. package/esm/presentation/drill/hooks/useDrillSelectDropdownMenuItems.js +1 -5
  50. package/esm/presentation/export/DefaultDashboardExportVariables.js +5 -2
  51. package/esm/presentation/export/hooks/useDashboardRelatedFilters.d.ts +2 -1
  52. package/esm/presentation/export/hooks/useDashboardRelatedFilters.js +9 -0
  53. package/esm/presentation/export/types.d.ts +2 -1
  54. package/esm/presentation/export/types.js +1 -1
  55. package/esm/presentation/export/useExportData.js +4 -0
  56. package/esm/presentation/filterBar/attributeFilter/DefaultDashboardAttributeFilter.js +4 -1
  57. package/esm/presentation/filterBar/filterBar/DefaultDashboardFilterGroup.js +4 -1
  58. package/esm/presentation/localization/bundles/de-DE.localization-bundle.d.ts +3 -9
  59. package/esm/presentation/localization/bundles/de-DE.localization-bundle.js +3 -9
  60. package/esm/presentation/localization/bundles/en-AU.localization-bundle.d.ts +3 -9
  61. package/esm/presentation/localization/bundles/en-AU.localization-bundle.js +3 -9
  62. package/esm/presentation/localization/bundles/en-GB.localization-bundle.d.ts +3 -9
  63. package/esm/presentation/localization/bundles/en-GB.localization-bundle.js +4 -10
  64. package/esm/presentation/localization/bundles/en-US.localization-bundle.d.ts +4 -36
  65. package/esm/presentation/localization/bundles/en-US.localization-bundle.js +4 -36
  66. package/esm/presentation/localization/bundles/es-419.localization-bundle.d.ts +3 -9
  67. package/esm/presentation/localization/bundles/es-419.localization-bundle.js +4 -10
  68. package/esm/presentation/localization/bundles/es-ES.localization-bundle.d.ts +3 -9
  69. package/esm/presentation/localization/bundles/es-ES.localization-bundle.js +4 -10
  70. package/esm/presentation/localization/bundles/fi-FI.localization-bundle.d.ts +3 -9
  71. package/esm/presentation/localization/bundles/fi-FI.localization-bundle.js +3 -9
  72. package/esm/presentation/localization/bundles/fr-CA.localization-bundle.d.ts +3 -9
  73. package/esm/presentation/localization/bundles/fr-CA.localization-bundle.js +3 -9
  74. package/esm/presentation/localization/bundles/fr-FR.localization-bundle.d.ts +3 -9
  75. package/esm/presentation/localization/bundles/fr-FR.localization-bundle.js +3 -9
  76. package/esm/presentation/localization/bundles/id-ID.localization-bundle.d.ts +3 -9
  77. package/esm/presentation/localization/bundles/id-ID.localization-bundle.js +3 -9
  78. package/esm/presentation/localization/bundles/it-IT.localization-bundle.d.ts +3 -9
  79. package/esm/presentation/localization/bundles/it-IT.localization-bundle.js +3 -9
  80. package/esm/presentation/localization/bundles/ja-JP.localization-bundle.d.ts +3 -9
  81. package/esm/presentation/localization/bundles/ja-JP.localization-bundle.js +3 -9
  82. package/esm/presentation/localization/bundles/ko-KR.localization-bundle.d.ts +3 -9
  83. package/esm/presentation/localization/bundles/ko-KR.localization-bundle.js +3 -9
  84. package/esm/presentation/localization/bundles/nl-NL.localization-bundle.d.ts +3 -9
  85. package/esm/presentation/localization/bundles/nl-NL.localization-bundle.js +3 -9
  86. package/esm/presentation/localization/bundles/pl-PL.localization-bundle.d.ts +3 -9
  87. package/esm/presentation/localization/bundles/pl-PL.localization-bundle.js +3 -9
  88. package/esm/presentation/localization/bundles/pt-BR.localization-bundle.d.ts +3 -9
  89. package/esm/presentation/localization/bundles/pt-BR.localization-bundle.js +3 -9
  90. package/esm/presentation/localization/bundles/pt-PT.localization-bundle.d.ts +3 -9
  91. package/esm/presentation/localization/bundles/pt-PT.localization-bundle.js +3 -9
  92. package/esm/presentation/localization/bundles/ru-RU.localization-bundle.d.ts +3 -9
  93. package/esm/presentation/localization/bundles/ru-RU.localization-bundle.js +3 -9
  94. package/esm/presentation/localization/bundles/sl-SI.localization-bundle.d.ts +3 -9
  95. package/esm/presentation/localization/bundles/sl-SI.localization-bundle.js +3 -9
  96. package/esm/presentation/localization/bundles/th-TH.localization-bundle.d.ts +3 -9
  97. package/esm/presentation/localization/bundles/th-TH.localization-bundle.js +3 -9
  98. package/esm/presentation/localization/bundles/tr-TR.localization-bundle.d.ts +3 -9
  99. package/esm/presentation/localization/bundles/tr-TR.localization-bundle.js +3 -9
  100. package/esm/presentation/localization/bundles/uk-UA.localization-bundle.d.ts +3 -9
  101. package/esm/presentation/localization/bundles/uk-UA.localization-bundle.js +3 -9
  102. package/esm/presentation/localization/bundles/vi-VN.localization-bundle.d.ts +3 -9
  103. package/esm/presentation/localization/bundles/vi-VN.localization-bundle.js +3 -9
  104. package/esm/presentation/localization/bundles/zh-HK.localization-bundle.d.ts +3 -9
  105. package/esm/presentation/localization/bundles/zh-HK.localization-bundle.js +3 -9
  106. package/esm/presentation/localization/bundles/zh-Hans.localization-bundle.d.ts +3 -9
  107. package/esm/presentation/localization/bundles/zh-Hans.localization-bundle.js +3 -9
  108. package/esm/presentation/localization/bundles/zh-Hant.localization-bundle.d.ts +3 -9
  109. package/esm/presentation/localization/bundles/zh-Hant.localization-bundle.js +3 -9
  110. package/esm/presentation/scheduledEmail/DefaultScheduledEmailDialog/DefaultScheduledEmailDialog.js +26 -59
  111. package/esm/presentation/scheduledEmail/DefaultScheduledEmailDialog/hooks/useEditScheduledEmail.d.ts +2 -6
  112. package/esm/presentation/scheduledEmail/DefaultScheduledEmailDialog/hooks/useEditScheduledEmail.js +22 -104
  113. package/esm/presentation/scheduledEmail/DefaultScheduledEmailDialog/hooks/useSaveScheduledEmailToBackend.js +12 -33
  114. package/esm/presentation/scheduledEmail/hooks/useWidgetAutomationFilters.d.ts +3 -0
  115. package/esm/presentation/scheduledEmail/hooks/useWidgetAutomationFilters.js +46 -0
  116. package/esm/presentation/scheduledEmail/types.d.ts +1 -7
  117. package/esm/presentation/scheduledEmail/utils/filters.d.ts +2 -0
  118. package/esm/presentation/scheduledEmail/utils/filters.js +5 -0
  119. package/esm/presentation/shareDialog/DefaultShareDialog.d.ts +1 -1
  120. package/esm/presentation/shareDialog/DefaultShareDialog.js +2 -2
  121. package/esm/presentation/shareDialog/types.d.ts +5 -1
  122. package/esm/presentation/widget/insight/configuration/DrillTargets/useInvalidFilteringParametersIdentifiers.d.ts +2 -2
  123. package/esm/presentation/widget/insight/configuration/DrillTargets/useInvalidFilteringParametersIdentifiers.js +36 -5
  124. package/esm/presentation/widget/insight/configuration/InsightAlertConfig/EditAlert.js +2 -2
  125. package/esm/presentation/widget/insight/configuration/InsightAlertConfig/hooks/useInsightWidgetAlerting.js +3 -6
  126. package/esm/presentation/widget/insight/configuration/InsightAlerts.js +1 -9
  127. package/esm/presentation/widget/insight/configuration/InsightDrillConfigPanel/useInsightDrillConfigPanel.js +4 -10
  128. package/esm/sdk-ui-dashboard.d.ts +31 -249
  129. package/package.json +20 -20
  130. package/esm/model/react/filtering/shared.d.ts +0 -6
  131. package/esm/model/react/filtering/shared.js +0 -38
  132. package/esm/model/react/filtering/useAutomationAvailableDashboardFilters.d.ts +0 -13
  133. package/esm/model/react/filtering/useAutomationAvailableDashboardFilters.js +0 -54
  134. package/esm/model/react/filtering/useDashboardScheduledExportFilters.d.ts +0 -19
  135. package/esm/model/react/filtering/useDashboardScheduledExportFilters.js +0 -18
  136. package/esm/model/react/filtering/useScheduledExportFilters.d.ts +0 -26
  137. package/esm/model/react/filtering/useScheduledExportFilters.js +0 -23
  138. package/esm/model/react/filtering/useWidgetAlertFilters.d.ts +0 -33
  139. package/esm/model/react/filtering/useWidgetAlertFilters.js +0 -48
  140. package/esm/model/react/filtering/useWidgetScheduledExportFilters.d.ts +0 -33
  141. package/esm/model/react/filtering/useWidgetScheduledExportFilters.js +0 -48
  142. package/esm/model/react/useDashboardAlerting/useEnableAutomationFilterContext.d.ts +0 -4
  143. package/esm/model/react/useDashboardAlerting/useEnableAutomationFilterContext.js +0 -20
  144. package/esm/model/react/useDashboardAlertsOld.d.ts +0 -32
  145. package/esm/model/react/useDashboardAlertsOld.js +0 -141
  146. package/esm/presentation/alerting/DefaultAlertingDialog/DefaultAlertingDialogOld.d.ts +0 -5
  147. package/esm/presentation/alerting/DefaultAlertingDialog/DefaultAlertingDialogOld.js +0 -36
  148. package/esm/presentation/alerting/DefaultAlertingDialog/components/AlertAttributeSelectOld.d.ts +0 -17
  149. package/esm/presentation/alerting/DefaultAlertingDialog/components/AlertAttributeSelectOld.js +0 -103
  150. package/esm/presentation/alerting/DefaultAlertingManagementDialog/DefaultAlertingManagementDialogOld.d.ts +0 -5
  151. package/esm/presentation/alerting/DefaultAlertingManagementDialog/DefaultAlertingManagementDialogOld.js +0 -53
  152. package/esm/presentation/alerting/DefaultAlertingManagementDialog/components/AlertOld.d.ts +0 -9
  153. package/esm/presentation/alerting/DefaultAlertingManagementDialog/components/AlertOld.js +0 -84
  154. package/esm/presentation/alerting/DefaultAlertingManagementDialog/components/AlertsListOld.d.ts +0 -11
  155. package/esm/presentation/alerting/DefaultAlertingManagementDialog/components/AlertsListOld.js +0 -16
  156. package/esm/presentation/dashboard/DashboardHeader/AlertingDialogProviderOld.d.ts +0 -1
  157. package/esm/presentation/dashboard/DashboardHeader/AlertingDialogProviderOld.js +0 -12
  158. package/esm/presentation/scheduledEmail/DefaultScheduledEmailDialog/components/AttachmentsOld/AttachmentFilters.d.ts +0 -29
  159. package/esm/presentation/scheduledEmail/DefaultScheduledEmailDialog/components/AttachmentsOld/AttachmentFilters.js +0 -61
  160. package/esm/presentation/scheduledEmail/DefaultScheduledEmailDialog/components/AttachmentsOld/AttachmentFiltersList.d.ts +0 -6
  161. package/esm/presentation/scheduledEmail/DefaultScheduledEmailDialog/components/AttachmentsOld/AttachmentFiltersList.js +0 -12
  162. package/esm/presentation/scheduledEmail/DefaultScheduledEmailDialog/components/AttachmentsOld/AttachmentItems.d.ts +0 -17
  163. package/esm/presentation/scheduledEmail/DefaultScheduledEmailDialog/components/AttachmentsOld/AttachmentItems.js +0 -68
  164. package/esm/presentation/scheduledEmail/DefaultScheduledEmailDialog/components/AttachmentsOld/AttachmentsWrapper.d.ts +0 -4
  165. package/esm/presentation/scheduledEmail/DefaultScheduledEmailDialog/components/AttachmentsOld/AttachmentsWrapper.js +0 -6
  166. package/esm/presentation/scheduledEmail/DefaultScheduledEmailDialog/components/AttachmentsOld/DashboardAttachments.d.ts +0 -15
  167. package/esm/presentation/scheduledEmail/DefaultScheduledEmailDialog/components/AttachmentsOld/DashboardAttachments.js +0 -42
  168. package/esm/presentation/scheduledEmail/DefaultScheduledEmailDialog/components/AttachmentsOld/WidgetAttachments.d.ts +0 -18
  169. package/esm/presentation/scheduledEmail/DefaultScheduledEmailDialog/components/AttachmentsOld/WidgetAttachments.js +0 -25
  170. package/esm/presentation/scheduledEmail/DefaultScheduledEmailDialog/types.d.ts +0 -2
  171. package/esm/presentation/scheduledEmail/DefaultScheduledEmailDialog/types.js +0 -2
  172. package/esm/presentation/widget/insight/configuration/InsightAlertsOld.d.ts +0 -2
  173. package/esm/presentation/widget/insight/configuration/InsightAlertsOld.js +0 -43
@@ -5,15 +5,16 @@ import { HighlightStyle, StreamLanguage, syntaxHighlighting } from "@codemirror/
5
5
  import { Tag } from "@lezer/highlight";
6
6
  import { compact, uniqBy } from "lodash-es";
7
7
  import { FormattedMessage, useIntl } from "react-intl";
8
- import { filterObjRef, idRef, isArbitraryAttributeFilter, isAttributeFilter, isMatchAttributeFilter, isNegativeAttributeFilter, isPositiveAttributeFilter, isUriRef, objRefToString, serializeObjRef, } from "@gooddata/sdk-model";
8
+ import { filterObjRef, idRef, insightFilters as insightDefinitionFilters, isArbitraryAttributeFilter, isAttributeFilter, isMatchAttributeFilter, isMeasureValueFilter, isNegativeAttributeFilter, isPositiveAttributeFilter, isUriRef, objRefToString, serializeObjRef, } from "@gooddata/sdk-model";
9
9
  import { ConfirmDialogBase, FullScreenOverlay, Overlay, OverlayController, OverlayControllerProvider, SyntaxHighlightingInput, useMediaQuery, } from "@gooddata/sdk-ui-kit";
10
10
  import { dashboardAttributeFilterItemToAttributeFilter } from "../../../../converters/filterConverters.js";
11
11
  import { useDashboardSelector } from "../../../../model/react/DashboardStoreProvider.js";
12
12
  import { useWidgetFilters } from "../../../../model/react/useWidgetFilters.js";
13
- import { selectAllCatalogDisplayFormsMap } from "../../../../model/store/catalog/catalogSelectors.js";
14
- import { selectIsWhiteLabeled } from "../../../../model/store/config/configSelectors.js";
13
+ import { selectAllCatalogDisplayFormsMap, selectAllCatalogMeasuresMap, } from "../../../../model/store/catalog/catalogSelectors.js";
14
+ import { selectEnableMeasureValueFilterKD, selectIsWhiteLabeled, } from "../../../../model/store/config/configSelectors.js";
15
+ import { selectInsightByWidgetRef } from "../../../../model/store/insights/insightsSelectors.js";
15
16
  import { selectAttributeFilterConfigsOverrides } from "../../../../model/store/tabs/attributeFilterConfigs/attributeFilterConfigsSelectors.js";
16
- import { selectFilterContextAttributeFilterItems } from "../../../../model/store/tabs/filterContext/filterContextSelectors.js";
17
+ import { selectFilterContextAttributeFilterItems, selectFilterContextMeasureValueFilters, } from "../../../../model/store/tabs/filterContext/filterContextSelectors.js";
17
18
  import { selectFilterableWidgetByRef } from "../../../../model/store/tabs/layout/layoutSelectors.js";
18
19
  import { DASHBOARD_HEADER_OVERLAYS_Z_INDEX } from "../../../constants/zIndex.js";
19
20
  import { useInvalidFilteringParametersIdentifiers } from "../../../widget/insight/configuration/DrillTargets/useInvalidFilteringParametersIdentifiers.js";
@@ -114,6 +115,30 @@ const buildValidDashboardFiltersFormattingRule = (attributeFilters, attributeFil
114
115
  token: customTags.filter.toString(),
115
116
  };
116
117
  };
118
+ const buildValidDashboardMvfFormattingRule = (measureIdentifiers) => {
119
+ if (measureIdentifiers.length === 0) {
120
+ return undefined;
121
+ }
122
+ const validDashboardMvfPlaceholders = measureIdentifiers
123
+ .map((id) => `{dash_mvf_condition\\(${id}\\)}`)
124
+ .join("|");
125
+ return {
126
+ regex: new RegExp(`^${validDashboardMvfPlaceholders}`),
127
+ token: customTags.filter.toString(),
128
+ };
129
+ };
130
+ const buildValidInsightMvfFormattingRule = (measureIdentifiers) => {
131
+ if (measureIdentifiers.length === 0) {
132
+ return undefined;
133
+ }
134
+ const validInsightMvfPlaceholders = measureIdentifiers
135
+ .map((id) => `{mvf_condition\\(${id}\\)}`)
136
+ .join("|");
137
+ return {
138
+ regex: new RegExp(`^${validInsightMvfPlaceholders}`),
139
+ token: customTags.filter.toString(),
140
+ };
141
+ };
117
142
  const IDENTIFIER_RULE = {
118
143
  regex: /^\{workspace_id\}|\{project_id\}|\{visualization_id\}|\{widget_id\}|\{dashboard_id\}|\{client_id\}|\{data_product_id\}/,
119
144
  token: customTags.identifier.toString(),
@@ -127,6 +152,14 @@ const INVALID_DASHBOARD_ATTRIBUTE_FILTER_RULE = {
127
152
  regex: /^\{dash_attribute_filter_selection\(.*?\)\}/,
128
153
  token: customTags.invalidFilter.toString(),
129
154
  };
155
+ const INVALID_DASHBOARD_MVF_RULE = {
156
+ regex: /^\{dash_mvf_condition\(.*?\)\}/,
157
+ token: customTags.invalidFilter.toString(),
158
+ };
159
+ const INVALID_INSIGHT_MVF_RULE = {
160
+ regex: /^\{mvf_condition\(.*?\)\}/,
161
+ token: customTags.invalidFilter.toString(),
162
+ };
130
163
  const INVALID_INSIGHT_ATTRIBUTE_FILTER_RULE = {
131
164
  regex: /^\{attribute_filter_selection\(.*?\)\}/,
132
165
  token: customTags.invalidFilter.toString(),
@@ -134,27 +167,55 @@ const INVALID_INSIGHT_ATTRIBUTE_FILTER_RULE = {
134
167
  const DEFAULT_RULES = [
135
168
  INVALID_DISPLAY_FORMS_RULE,
136
169
  INVALID_DASHBOARD_ATTRIBUTE_FILTER_RULE,
170
+ INVALID_DASHBOARD_MVF_RULE,
171
+ INVALID_INSIGHT_MVF_RULE,
137
172
  INVALID_INSIGHT_ATTRIBUTE_FILTER_RULE,
138
173
  IDENTIFIER_RULE,
139
174
  INVALID_IDENTIFIER_RULE,
140
175
  ];
141
- const buildFormattingRules = (attributeDisplayForms, dashboardFilters, insightFilters, attributeFilterConfigs) => {
176
+ const buildFormattingRules = (attributeDisplayForms, dashboardFilters, insightFilters, dashboardMeasureIdentifiers, insightMeasureIdentifiers, attributeFilterConfigs) => {
142
177
  const validDisplayFormsRule = buildValidDisplayFormsFormattingRule(attributeDisplayForms);
143
178
  const validInsightFiltersRule = buildValidInsightFiltersFormattingRule(insightFilters);
144
179
  const validDashboardFiltersRule = buildValidDashboardFiltersFormattingRule(dashboardFilters, attributeFilterConfigs);
180
+ const validDashboardMvfRule = buildValidDashboardMvfFormattingRule(dashboardMeasureIdentifiers);
181
+ const validInsightMvfRule = buildValidInsightMvfFormattingRule(insightMeasureIdentifiers);
145
182
  return compact([
146
183
  validDisplayFormsRule,
147
184
  validDashboardFiltersRule,
185
+ validDashboardMvfRule,
148
186
  validInsightFiltersRule,
187
+ validInsightMvfRule,
149
188
  ...DEFAULT_RULES,
150
189
  ]);
151
190
  };
152
- function UrlInputPanel({ currentUrlValue, onChange, onCursor, documentationLink, attributeDisplayForms, intl, insightFilters, dashboardFilters, attributeFilterConfigs, }) {
191
+ function UrlInputPanel({ currentUrlValue, onChange, onCursor, documentationLink, attributeDisplayForms, intl, insightFilters, dashboardFilters, dashboardMeasureValueFilters, insightMeasureValueFilters, enableInsightMeasureValueFilters, attributeFilterConfigs, }) {
153
192
  const isWhiteLabeled = useDashboardSelector(selectIsWhiteLabeled);
193
+ const catalogMeasuresMap = useDashboardSelector(selectAllCatalogMeasuresMap);
194
+ const dashboardMeasureIdentifiers = useMemo(() => {
195
+ return (dashboardMeasureValueFilters ?? []).map((filter) => {
196
+ const measureRef = filter.dashboardMeasureValueFilter.measure;
197
+ return catalogMeasuresMap.get(measureRef)?.measure.id ?? objRefToString(measureRef);
198
+ });
199
+ }, [catalogMeasuresMap, dashboardMeasureValueFilters]);
200
+ const insightMeasureIdentifiers = useMemo(() => enableInsightMeasureValueFilters
201
+ ? (insightMeasureValueFilters ?? []).map((filter) => {
202
+ const measureRef = filter.measureValueFilter.measure;
203
+ return objRefToString(measureRef);
204
+ })
205
+ : [], [enableInsightMeasureValueFilters, insightMeasureValueFilters]);
154
206
  const syntaxHighlightingRules = useMemo(() => attributeDisplayForms &&
155
207
  insightFilters &&
156
208
  dashboardFilters &&
157
- buildFormattingRules(attributeDisplayForms, dashboardFilters, insightFilters, attributeFilterConfigs), [attributeDisplayForms, insightFilters, dashboardFilters, attributeFilterConfigs]);
209
+ dashboardMeasureValueFilters &&
210
+ buildFormattingRules(attributeDisplayForms, dashboardFilters, insightFilters, dashboardMeasureIdentifiers, insightMeasureIdentifiers, attributeFilterConfigs), [
211
+ attributeDisplayForms,
212
+ insightFilters,
213
+ dashboardFilters,
214
+ dashboardMeasureValueFilters,
215
+ dashboardMeasureIdentifiers,
216
+ insightMeasureIdentifiers,
217
+ attributeFilterConfigs,
218
+ ]);
158
219
  return (_jsxs("div", { children: [
159
220
  _jsx("label", { className: "gd-label", children: _jsx(FormattedMessage, { id: "configurationPanel.drillIntoUrl.editor.textAreaLabel" }) }), _jsx(UrlInput, { onChange: onChange, onCursor: onCursor, currentUrlValue: currentUrlValue, syntaxHighlightingRules: syntaxHighlightingRules, intl: intl }), !isWhiteLabeled && documentationLink ? _jsx(HelpLink, { link: documentationLink }) : null] }));
160
221
  }
@@ -163,19 +224,33 @@ const initialCursorPosition = {
163
224
  to: 0,
164
225
  };
165
226
  const insertPlaceholderAtCursor = (text, placeholder, cursor) => `${text.substring(0, cursor.from)}${placeholder}${text.substring(cursor.to)}`;
166
- const assertValidUrl = (url) => /^[A-Za-z0-9.\-+]+:|^\{attribute_title\(|^\{attribute_filter_selection\(|^\{dash_attribute_filter_selection\(/.test(url)
167
- ? url
168
- : `https://${url}`;
227
+ const URL_START_RULES = [
228
+ /^[A-Za-z0-9.\-+]+:/,
229
+ /^\{attribute_title\(/,
230
+ /^\{attribute_filter_selection\(/,
231
+ /^\{dash_attribute_filter_selection\(/,
232
+ /^\{dash_mvf_condition\(/,
233
+ ];
234
+ const INSIGHT_MVF_URL_START_RULE = /^\{mvf_condition\(/;
235
+ const assertValidUrl = (url, enableInsightMeasureValueFilters) => {
236
+ const rules = enableInsightMeasureValueFilters
237
+ ? [...URL_START_RULES, INSIGHT_MVF_URL_START_RULE]
238
+ : URL_START_RULES;
239
+ return rules.some((rule) => rule.test(url)) ? url : `https://${url}`;
240
+ };
169
241
  const getWarningTextForInvalidParameters = (parameters) => {
170
242
  const invalidParameters = parameters.map((parameter) => `"${parameter}"`).join(", ");
171
243
  return (_jsx(FormattedMessage, { id: "configurationPanel.drillIntoUrl.editor.invalidAttributeDisplayForms", values: { invalidParameters } }));
172
244
  };
173
245
  function CustomUrlEditorDialog({ urlDrillTarget, documentationLink, onSelect, onClose, attributeDisplayForms, loadingAttributeDisplayForms = false, invalidAttributeDisplayFormIdentifiers, enableClientIdParameter, enableDataProductIdParameter, enableWidgetIdParameter, widgetRef, }) {
174
246
  const intl = useIntl();
247
+ const enableInsightMeasureValueFilters = useDashboardSelector(selectEnableMeasureValueFilterKD);
175
248
  const insightFilters = useSanitizedInsightFilters(widgetRef);
249
+ const insightMeasureValueFilters = useInsightMeasureValueFilters(widgetRef, enableInsightMeasureValueFilters);
176
250
  const dashboardFilters = useSanitizedDashboardFilters();
251
+ const dashboardMeasureValueFilters = useDashboardSelector(selectFilterContextMeasureValueFilters);
177
252
  const attributeFilterConfigs = useDashboardSelector(selectAttributeFilterConfigsOverrides);
178
- const invalidFilteringParametersIdentifiers = useInvalidFilteringParametersIdentifiers(urlDrillTarget, insightFilters, dashboardFilters, attributeFilterConfigs);
253
+ const invalidFilteringParametersIdentifiers = useInvalidFilteringParametersIdentifiers(urlDrillTarget, insightFilters, dashboardFilters, dashboardMeasureValueFilters, enableInsightMeasureValueFilters ? insightMeasureValueFilters : undefined, enableInsightMeasureValueFilters, attributeFilterConfigs);
179
254
  const invalidParameters = useMemo(() => {
180
255
  return [...invalidAttributeDisplayFormIdentifiers, ...invalidFilteringParametersIdentifiers];
181
256
  }, [invalidAttributeDisplayFormIdentifiers, invalidFilteringParametersIdentifiers]);
@@ -183,7 +258,7 @@ function CustomUrlEditorDialog({ urlDrillTarget, documentationLink, onSelect, on
183
258
  ? (isDrillToCustomUrlConfig(urlDrillTarget) && urlDrillTarget.customUrl) || ""
184
259
  : "";
185
260
  const [currentValue, setCurrentValue] = useState(previousValue);
186
- const apply = () => onSelect(assertValidUrl(currentValue));
261
+ const apply = () => onSelect(assertValidUrl(currentValue, enableInsightMeasureValueFilters));
187
262
  const handleOnChange = (value) => setCurrentValue(value);
188
263
  const isApplyEnabled = currentValue && currentValue.localeCompare(previousValue) !== 0;
189
264
  const [cursorPosition, setCursorPosition] = useState(initialCursorPosition);
@@ -197,7 +272,7 @@ function CustomUrlEditorDialog({ urlDrillTarget, documentationLink, onSelect, on
197
272
  }), submitButtonText: intl.formatMessage({
198
273
  id: "configurationPanel.drillIntoUrl.editor.applyButtonLabel",
199
274
  }), isSubmitDisabled: !isApplyEnabled, submitOnEnterKey: false, onCancel: onClose, onSubmit: apply, warning: editorWarningText, children: [
200
- _jsx(UrlInputPanel, { onChange: handleOnChange, onCursor: handleCursorPosition, documentationLink: documentationLink, currentUrlValue: currentValue, attributeDisplayForms: attributeDisplayForms, insightFilters: insightFilters, dashboardFilters: dashboardFilters, attributeFilterConfigs: attributeFilterConfigs, intl: intl }), _jsx(ParametersPanel, { insightFilters: insightFilters, dashboardFilters: dashboardFilters, attributeFilterConfigs: attributeFilterConfigs, attributeDisplayForms: attributeDisplayForms, loadingAttributeDisplayForms: loadingAttributeDisplayForms, enableClientIdParameter: enableClientIdParameter, enableDataProductIdParameter: enableDataProductIdParameter, enableWidgetIdParameter: enableWidgetIdParameter, onAdd: handleOnAdd, intl: intl, widgetRef: widgetRef })
275
+ _jsx(UrlInputPanel, { onChange: handleOnChange, onCursor: handleCursorPosition, documentationLink: documentationLink, currentUrlValue: currentValue, attributeDisplayForms: attributeDisplayForms, insightFilters: insightFilters, dashboardFilters: dashboardFilters, dashboardMeasureValueFilters: dashboardMeasureValueFilters, insightMeasureValueFilters: insightMeasureValueFilters, enableInsightMeasureValueFilters: enableInsightMeasureValueFilters, attributeFilterConfigs: attributeFilterConfigs, intl: intl }), _jsx(ParametersPanel, { insightFilters: insightFilters, dashboardFilters: dashboardFilters, dashboardMeasureValueFilters: dashboardMeasureValueFilters, insightMeasureValueFilters: insightMeasureValueFilters, attributeFilterConfigs: attributeFilterConfigs, attributeDisplayForms: attributeDisplayForms, loadingAttributeDisplayForms: loadingAttributeDisplayForms, enableClientIdParameter: enableClientIdParameter, enableDataProductIdParameter: enableDataProductIdParameter, enableWidgetIdParameter: enableWidgetIdParameter, onAdd: handleOnAdd, intl: intl, widgetRef: widgetRef })
201
276
  ] }));
202
277
  }
203
278
  const overlayController = OverlayController.getInstance(DASHBOARD_HEADER_OVERLAYS_Z_INDEX);
@@ -206,6 +281,15 @@ export function CustomUrlEditor(props) {
206
281
  const SelectedOverlay = isMobileDevice ? FullScreenOverlay : Overlay;
207
282
  return (_jsx(OverlayControllerProvider, { overlayController: overlayController, children: _jsx(SelectedOverlay, { onClose: props.onClose, isModal: true, closeOnOutsideClick: false, closeOnEscape: true, positionType: "fixed", className: "gd-modal-overlay", children: _jsx(CustomUrlEditorDialog, { ...props }) }) }));
208
283
  }
284
+ function useInsightMeasureValueFilters(widgetRef, enabled) {
285
+ const insight = useDashboardSelector(selectInsightByWidgetRef(widgetRef));
286
+ return useMemo(() => {
287
+ if (!enabled || !insight) {
288
+ return [];
289
+ }
290
+ return insightDefinitionFilters(insight).filter(isMeasureValueFilter);
291
+ }, [enabled, insight]);
292
+ }
209
293
  function useSanitizedInsightFilters(widgetRef) {
210
294
  const widget = useDashboardSelector(selectFilterableWidgetByRef(widgetRef));
211
295
  const widgetFiltersResult = useWidgetFilters(widget);
@@ -2,5 +2,5 @@ import { type IDashboardParametersSectionProps } from "./CustomUrlEditorParamete
2
2
  import { type IInsightParametersSectionProps } from "./CustomUrlEditorParametersSections/InsightParametersSection.js";
3
3
  import { type IIdentifierParametersSectionProps } from "./types.js";
4
4
  type IParametersPanelProps = IInsightParametersSectionProps & IIdentifierParametersSectionProps & IDashboardParametersSectionProps;
5
- export declare function ParametersPanel({ attributeDisplayForms, loadingAttributeDisplayForms, enableClientIdParameter, enableDataProductIdParameter, enableWidgetIdParameter, onAdd, intl, dashboardFilters, attributeFilterConfigs, insightFilters, widgetRef }: IParametersPanelProps): import("react/jsx-runtime").JSX.Element;
5
+ export declare function ParametersPanel({ attributeDisplayForms, loadingAttributeDisplayForms, enableClientIdParameter, enableDataProductIdParameter, enableWidgetIdParameter, onAdd, intl, dashboardFilters, dashboardMeasureValueFilters, insightMeasureValueFilters, attributeFilterConfigs, insightFilters, widgetRef }: IParametersPanelProps): import("react/jsx-runtime").JSX.Element;
6
6
  export {};
@@ -1,18 +1,18 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- // (C) 2020-2025 GoodData Corporation
2
+ // (C) 2020-2026 GoodData Corporation
3
3
  import { FormattedMessage } from "react-intl";
4
4
  import { Bubble, BubbleHoverTrigger } from "@gooddata/sdk-ui-kit";
5
5
  import { DashboardParametersSection, } from "./CustomUrlEditorParametersSections/DashboardParametersSection.js";
6
6
  import { IdentifierParametersSection } from "./CustomUrlEditorParametersSections/IdentifierParametersSection.js";
7
7
  import { InsightParametersSection, } from "./CustomUrlEditorParametersSections/InsightParametersSection.js";
8
- export function ParametersPanel({ attributeDisplayForms, loadingAttributeDisplayForms, enableClientIdParameter, enableDataProductIdParameter, enableWidgetIdParameter, onAdd, intl, dashboardFilters, attributeFilterConfigs, insightFilters, widgetRef, }) {
8
+ export function ParametersPanel({ attributeDisplayForms, loadingAttributeDisplayForms, enableClientIdParameter, enableDataProductIdParameter, enableWidgetIdParameter, onAdd, intl, dashboardFilters, dashboardMeasureValueFilters, insightMeasureValueFilters, attributeFilterConfigs, insightFilters, widgetRef, }) {
9
9
  return (_jsxs("div", { children: [
10
10
  _jsxs("label", { className: "gd-label", children: [
11
11
  _jsx(FormattedMessage, { id: "configurationPanel.drillIntoUrl.editor.parametersPanelLabel" }), _jsxs(BubbleHoverTrigger, { className: "gd-list-item-tooltip", showDelay: 0, hideDelay: 0, children: [
12
12
  _jsx("span", { className: "gd-icon-circle-question gd-list-item-tooltip-icon" }), _jsx(Bubble, { className: "bubble-primary", alignPoints: [{ align: "cr cl" }], children: _jsx(FormattedMessage, { id: "configurationPanel.drillIntoUrl.editor.parametersPanelTooltip" }) })
13
13
  ] })
14
14
  ] }), _jsxs("div", { className: "gd-drill-to-url-parameters gd-drill-to-url-list", children: [
15
- _jsx(InsightParametersSection, { attributeDisplayForms: attributeDisplayForms, loadingAttributeDisplayForms: loadingAttributeDisplayForms, onAdd: onAdd, intl: intl, insightFilters: insightFilters }), _jsx(DashboardParametersSection, { intl: intl, onAdd: onAdd, dashboardFilters: dashboardFilters, attributeFilterConfigs: attributeFilterConfigs }), _jsx(IdentifierParametersSection, { enableClientIdParameter: enableClientIdParameter, enableDataProductIdParameter: enableDataProductIdParameter, enableWidgetIdParameter: enableWidgetIdParameter, onAdd: onAdd, intl: intl, widgetRef: widgetRef })
15
+ _jsx(InsightParametersSection, { attributeDisplayForms: attributeDisplayForms, loadingAttributeDisplayForms: loadingAttributeDisplayForms, onAdd: onAdd, intl: intl, insightFilters: insightFilters, insightMeasureValueFilters: insightMeasureValueFilters, widgetRef: widgetRef }), _jsx(DashboardParametersSection, { intl: intl, onAdd: onAdd, dashboardFilters: dashboardFilters, dashboardMeasureValueFilters: dashboardMeasureValueFilters, attributeFilterConfigs: attributeFilterConfigs }), _jsx(IdentifierParametersSection, { enableClientIdParameter: enableClientIdParameter, enableDataProductIdParameter: enableDataProductIdParameter, enableWidgetIdParameter: enableWidgetIdParameter, onAdd: onAdd, intl: intl, widgetRef: widgetRef })
16
16
  ] })
17
17
  ] }));
18
18
  }
@@ -1,7 +1,8 @@
1
- import { type IAttributeFilter, type IDashboardAttributeFilterConfig } from "@gooddata/sdk-model";
1
+ import { type IAttributeFilter, type IDashboardAttributeFilterConfig, type IDashboardMeasureValueFilter } from "@gooddata/sdk-model";
2
2
  import { type IParametersPanelSectionsCommonProps } from "../types.js";
3
3
  export interface IDashboardParametersSectionProps extends IParametersPanelSectionsCommonProps {
4
4
  dashboardFilters?: IAttributeFilter[];
5
+ dashboardMeasureValueFilters?: IDashboardMeasureValueFilter[];
5
6
  attributeFilterConfigs?: IDashboardAttributeFilterConfig[];
6
7
  }
7
- export declare function DashboardParametersSection({ dashboardFilters, attributeFilterConfigs, onAdd }: IDashboardParametersSectionProps): import("react/jsx-runtime").JSX.Element | null;
8
+ export declare function DashboardParametersSection({ dashboardFilters, dashboardMeasureValueFilters, attributeFilterConfigs, intl, onAdd }: IDashboardParametersSectionProps): import("react/jsx-runtime").JSX.Element | null;
@@ -2,14 +2,19 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
2
2
  // (C) 2020-2026 GoodData Corporation
3
3
  import { Fragment } from "react";
4
4
  import { FormattedMessage } from "react-intl";
5
- import { filterLocalIdentifier, filterObjRef, } from "@gooddata/sdk-model";
5
+ import { filterLocalIdentifier, filterObjRef, objRefToString, } from "@gooddata/sdk-model";
6
+ import { MeasureValueFilterDetailsBubble } from "@gooddata/sdk-ui-filters/internal";
6
7
  import { useDashboardSelector } from "../../../../../model/react/DashboardStoreProvider.js";
7
- import { selectAllCatalogDisplayFormsMap } from "../../../../../model/store/catalog/catalogSelectors.js";
8
+ import { selectAllCatalogDisplayFormsMap, selectAllCatalogMeasuresMap, } from "../../../../../model/store/catalog/catalogSelectors.js";
8
9
  import { DropdownSectionHeader } from "../DropdownSectionHeader.js";
9
10
  import { DisplayFormParam } from "./DisplayFormParam.js";
10
- export function DashboardParametersSection({ dashboardFilters, attributeFilterConfigs, onAdd, }) {
11
+ import { Parameter } from "./Parameter.js";
12
+ export function DashboardParametersSection({ dashboardFilters, dashboardMeasureValueFilters, attributeFilterConfigs, intl, onAdd, }) {
11
13
  const catalogDisplayFormsMap = useDashboardSelector(selectAllCatalogDisplayFormsMap);
12
- return dashboardFilters && dashboardFilters.length > 0 ? (_jsxs(_Fragment, { children: [
14
+ const catalogMeasuresMap = useDashboardSelector(selectAllCatalogMeasuresMap);
15
+ const hasAttributeFilters = !!dashboardFilters?.length;
16
+ const hasMeasureValueFilters = !!dashboardMeasureValueFilters?.length;
17
+ return hasAttributeFilters || hasMeasureValueFilters ? (_jsxs(_Fragment, { children: [
13
18
  _jsx(DropdownSectionHeader, { children: _jsx(FormattedMessage, { id: "configurationPanel.drillIntoUrl.editor.dashboardParametersSectionLabel" }) }), dashboardFilters?.map((filter, index) => {
14
19
  const df = catalogDisplayFormsMap.get(filterObjRef(filter));
15
20
  const filterIdentifier = df?.id;
@@ -24,5 +29,13 @@ export function DashboardParametersSection({ dashboardFilters, attributeFilterCo
24
29
  }, isFilter: true })) : null, secondaryDf && areDfsDifferent ? (_jsx(DisplayFormParam, { item: secondaryDf, iconClassName: "gd-icon-filter", onAdd: () => {
25
30
  onAdd(`{dash_attribute_filter_selection(${filterSecondaryIdentifier})}`);
26
31
  }, isFilter: true })) : null] }, index));
32
+ }), dashboardMeasureValueFilters?.map((filter) => {
33
+ const { measure, localIdentifier, title } = filter.dashboardMeasureValueFilter;
34
+ const catalogMeasure = catalogMeasuresMap.get(measure);
35
+ const measureIdentifier = catalogMeasure?.measure.id ?? objRefToString(measure);
36
+ const measureTitle = title ?? catalogMeasure?.measure.title ?? measureIdentifier;
37
+ return (_jsx(Parameter, { name: measureTitle, description: measureIdentifier, detailTrigger: _jsx(MeasureValueFilterDetailsBubble, { title: measureTitle, requestHandler: catalogMeasure ? async () => catalogMeasure.measure : undefined }), iconClassName: "gd-icon-filter", onAdd: () => {
38
+ onAdd(`{dash_mvf_condition(${measureIdentifier})}`);
39
+ }, intl: intl }, localIdentifier));
27
40
  })] })) : null;
28
41
  }
@@ -1,8 +1,10 @@
1
- import { type IAttributeFilter } from "@gooddata/sdk-model";
1
+ import { type IAttributeFilter, type IMeasureValueFilter, type ObjRef } from "@gooddata/sdk-model";
2
2
  import { type IAttributeWithDisplayForm, type IParametersPanelSectionsCommonProps } from "../types.js";
3
3
  export interface IInsightParametersSectionProps extends IParametersPanelSectionsCommonProps {
4
4
  attributeDisplayForms?: IAttributeWithDisplayForm[];
5
5
  loadingAttributeDisplayForms: boolean;
6
6
  insightFilters?: IAttributeFilter[];
7
+ insightMeasureValueFilters?: IMeasureValueFilter[];
8
+ widgetRef: ObjRef;
7
9
  }
8
- export declare function InsightParametersSection({ attributeDisplayForms, loadingAttributeDisplayForms, insightFilters, onAdd }: IInsightParametersSectionProps): import("react/jsx-runtime").JSX.Element;
10
+ export declare function InsightParametersSection({ attributeDisplayForms, loadingAttributeDisplayForms, insightFilters, insightMeasureValueFilters, widgetRef, intl, onAdd }: IInsightParametersSectionProps): import("react/jsx-runtime").JSX.Element;
@@ -1,19 +1,52 @@
1
1
  import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  // (C) 2020-2026 GoodData Corporation
3
3
  import { FormattedMessage } from "react-intl";
4
- import { filterObjRef } from "@gooddata/sdk-model";
4
+ import { areObjRefsEqual, filterObjRef, insightMeasures, isLocalIdRef, measureAlias, measureItem, measureLocalId, measureTitle, objRefToString, } from "@gooddata/sdk-model";
5
+ import { MeasureValueFilterDetailsBubble } from "@gooddata/sdk-ui-filters/internal";
5
6
  import { useDashboardSelector } from "../../../../../model/react/DashboardStoreProvider.js";
6
- import { selectAllCatalogDisplayFormsMap } from "../../../../../model/store/catalog/catalogSelectors.js";
7
+ import { selectAllCatalogDisplayFormsMap, selectAllCatalogMeasuresMap, } from "../../../../../model/store/catalog/catalogSelectors.js";
8
+ import { selectInsightByWidgetRef } from "../../../../../model/store/insights/insightsSelectors.js";
7
9
  import { DropdownSectionHeader } from "../DropdownSectionHeader.js";
8
10
  import { DisplayFormParam } from "./DisplayFormParam.js";
9
- export function InsightParametersSection({ attributeDisplayForms, loadingAttributeDisplayForms, insightFilters, onAdd, }) {
11
+ import { Parameter } from "./Parameter.js";
12
+ export function InsightParametersSection({ attributeDisplayForms, loadingAttributeDisplayForms, insightFilters, insightMeasureValueFilters, widgetRef, intl, onAdd, }) {
10
13
  const catalogDisplayForms = useDashboardSelector(selectAllCatalogDisplayFormsMap);
14
+ const catalogMeasuresMap = useDashboardSelector(selectAllCatalogMeasuresMap);
15
+ const insight = useDashboardSelector(selectInsightByWidgetRef(widgetRef));
16
+ const measures = insight ? insightMeasures(insight) : [];
11
17
  return (_jsx(_Fragment, { children: (attributeDisplayForms && attributeDisplayForms.length > 0) ||
12
18
  loadingAttributeDisplayForms ||
13
- (insightFilters && insightFilters.length > 0) ? (_jsxs(_Fragment, { children: [
19
+ (insightFilters && insightFilters.length > 0) ||
20
+ (insightMeasureValueFilters && insightMeasureValueFilters.length > 0) ? (_jsxs(_Fragment, { children: [
14
21
  _jsx(DropdownSectionHeader, { children: _jsx(FormattedMessage, { id: "configurationPanel.drillIntoUrl.editor.insightParametersSectionLabel" }) }), loadingAttributeDisplayForms ? (_jsx("div", { className: "gd-drill-to-url-section-loading s-drill-to-custom-url-attr-section-loading", children: _jsx("div", { className: "gd-spinner small" }) })) : (attributeDisplayForms?.map((item) => (_jsx(DisplayFormParam, { item: item.displayForm, onAdd: onAdd }, item.displayForm.id)))), insightFilters?.map((filter, index) => {
15
22
  const displayFormRef = filterObjRef(filter);
16
23
  const df = catalogDisplayForms.get(displayFormRef);
17
24
  return (df && (_jsx(DisplayFormParam, { item: df, onAdd: () => onAdd(`{attribute_filter_selection(${df.id})}`), iconClassName: "gd-icon-filter", isFilter: true }, index)));
25
+ }), insightMeasureValueFilters?.map((filter) => {
26
+ const { measure, localIdentifier } = filter.measureValueFilter;
27
+ const insightMeasure = getInsightMeasure(measure, measures);
28
+ const insightMeasureItem = insightMeasure ? measureItem(insightMeasure) : undefined;
29
+ const catalogMeasure = isLocalIdRef(measure)
30
+ ? insightMeasureItem && catalogMeasuresMap.get(insightMeasureItem)
31
+ : catalogMeasuresMap.get(measure);
32
+ const measureIdentifier = objRefToString(measure);
33
+ const resolvedTitle = getInsightMeasureTitle(insightMeasure) ??
34
+ catalogMeasure?.measure.title ??
35
+ measureIdentifier;
36
+ return (_jsx(Parameter, { name: resolvedTitle, description: measureIdentifier, detailTrigger: _jsx(MeasureValueFilterDetailsBubble, { title: resolvedTitle, requestHandler: catalogMeasure ? async () => catalogMeasure.measure : undefined }), iconClassName: "gd-icon-filter", onAdd: () => {
37
+ onAdd(`{mvf_condition(${measureIdentifier})}`);
38
+ }, intl: intl }, localIdentifier ?? measureIdentifier));
18
39
  })] })) : null }));
19
40
  }
41
+ function getInsightMeasureTitle(measure) {
42
+ return measure ? (measureAlias(measure) ?? measureTitle(measure)) : undefined;
43
+ }
44
+ function getInsightMeasure(measureRef, measures) {
45
+ if (isLocalIdRef(measureRef)) {
46
+ return measures.find((measure) => measureLocalId(measure) === measureRef.localIdentifier);
47
+ }
48
+ return measures.find((measure) => {
49
+ const item = measureItem(measure);
50
+ return item ? areObjRefsEqual(item, measureRef) : false;
51
+ });
52
+ }
@@ -1,12 +1,13 @@
1
- import { type ReactElement } from "react";
1
+ import { type ReactElement, type ReactNode } from "react";
2
2
  import { type IntlShape } from "react-intl";
3
3
  interface IParameterProps {
4
4
  name: string;
5
5
  description?: string;
6
- detailContent: ReactElement;
6
+ detailContent?: ReactElement;
7
+ detailTrigger?: ReactNode;
7
8
  iconClassName: string;
8
9
  onAdd: () => void;
9
10
  intl: IntlShape;
10
11
  }
11
- export declare function Parameter({ name, description, detailContent, iconClassName, onAdd, intl }: IParameterProps): import("react/jsx-runtime").JSX.Element;
12
+ export declare function Parameter({ name, description, detailContent, detailTrigger, iconClassName, onAdd, intl }: IParameterProps): import("react/jsx-runtime").JSX.Element;
12
13
  export {};
@@ -5,7 +5,7 @@ import classNames from "classnames";
5
5
  import { Bubble, Button } from "@gooddata/sdk-ui-kit";
6
6
  import { isDarkTheme, useTheme } from "@gooddata/sdk-ui-theme-provider";
7
7
  import { simplifyText } from "@gooddata/util";
8
- export function Parameter({ name, description, detailContent, iconClassName, onAdd, intl }) {
8
+ export function Parameter({ name, description, detailContent, detailTrigger, iconClassName, onAdd, intl, }) {
9
9
  const [displayHelp, setDisplayHelp] = useState(false);
10
10
  const theme = useTheme();
11
11
  const isDark = theme && isDarkTheme(theme);
@@ -16,7 +16,6 @@ export function Parameter({ name, description, detailContent, iconClassName, onA
16
16
  id: "configurationPanel.drillIntoUrl.editor.addParameterButtonLabel",
17
17
  });
18
18
  return (_jsxs("div", { id: id, className: itemClassNames, onClick: () => onAdd(), children: [
19
- _jsx("span", { className: "gd-parameter-title", children: name }), description ? _jsxs("span", { className: "addon s-parameter-description", children: ["(", description, ")"] }) : null, _jsx(Button, { className: "gd-button gd-button-link s-parameter-add-button", value: addButtonLabel }), _jsxs("div", { className: "gd-list-item-tooltip", children: [
20
- _jsx("span", { className: "gd-icon-circle-question gd-list-item-tooltip-icon s-parameter-help-icon", onMouseEnter: () => setDisplayHelp(true), onMouseLeave: () => setDisplayHelp(false) }), displayHelp ? (_jsx(Bubble, { className: `themed-bubble ${isDark ? "bubble-primary" : "bubble-light"}`, alignTo: `#${id}`, alignPoints: [{ align: "cr tl" }], children: detailContent })) : null] })
21
- ] }));
19
+ _jsx("span", { className: "gd-parameter-title", children: name }), description ? _jsxs("span", { className: "addon s-parameter-description", children: ["(", description, ")"] }) : null, _jsx(Button, { className: "gd-button gd-button-link s-parameter-add-button", value: addButtonLabel }), detailTrigger ? (_jsx("div", { className: "gd-list-item-tooltip", onClick: (event) => event.stopPropagation(), children: detailTrigger })) : detailContent ? (_jsxs("div", { className: "gd-list-item-tooltip", children: [
20
+ _jsx("span", { className: "gd-icon-circle-question gd-list-item-tooltip-icon s-parameter-help-icon", onMouseEnter: () => setDisplayHelp(true), onMouseLeave: () => setDisplayHelp(false) }), displayHelp ? (_jsx(Bubble, { className: `themed-bubble ${isDark ? "bubble-primary" : "bubble-light"}`, alignTo: `#${id}`, alignPoints: [{ align: "cr tl" }], children: detailContent })) : null] })) : null] }));
22
21
  }
@@ -12,7 +12,6 @@ import { getDrillOriginLocalIdentifier } from "../../../_staging/drills/drilling
12
12
  import { useDashboardSelector } from "../../../model/react/DashboardStoreProvider.js";
13
13
  import { selectAccessibleDashboards } from "../../../model/store/accessibleDashboards/accessibleDashboardsSelectors.js";
14
14
  import { selectCatalogAttributeDisplayFormsById } from "../../../model/store/catalog/catalogSelectors.js";
15
- import { selectEnableImplicitDrillToUrl } from "../../../model/store/config/configSelectors.js";
16
15
  import { selectInsightsMap } from "../../../model/store/insights/insightsSelectors.js";
17
16
  import { selectDashboardTitle } from "../../../model/store/meta/metaSelectors.js";
18
17
  import { selectWidgetByRef } from "../../../model/store/tabs/layout/layoutSelectors.js";
@@ -32,7 +31,6 @@ export function DrillSelectDropdown({ isOpen, dropDownAnchorClass, onClose, onCl
32
31
  const insights = useDashboardSelector(selectInsightsMap);
33
32
  const widget = useDashboardSelector(selectWidgetByRef(drillEvent.widgetRef));
34
33
  const attributeDisplayForms = useDashboardSelector(selectCatalogAttributeDisplayFormsById);
35
- const enableImplicitDrillToUrl = useDashboardSelector(selectEnableImplicitDrillToUrl);
36
34
  const stopPropagation = useCallback((e) => {
37
35
  e.stopPropagation();
38
36
  }, []);
@@ -93,7 +91,7 @@ export function DrillSelectDropdown({ isOpen, dropDownAnchorClass, onClose, onCl
93
91
  if (isDrillDownDefinition(item.drillDefinition)) {
94
92
  return "drillDown";
95
93
  }
96
- if (isDrillToUrl(item.drillDefinition) && enableImplicitDrillToUrl) {
94
+ if (isDrillToUrl(item.drillDefinition)) {
97
95
  return "drillToUrl";
98
96
  }
99
97
  if (isCrossFiltering(item.drillDefinition)) {
@@ -1,8 +1,6 @@
1
1
  // (C) 2025-2026 GoodData Corporation
2
2
  import { useMemo } from "react";
3
3
  import { defineMessages, useIntl } from "react-intl";
4
- import { useDashboardSelector } from "../../../model/react/DashboardStoreProvider.js";
5
- import { selectEnableImplicitDrillToUrl } from "../../../model/store/config/configSelectors.js";
6
4
  import { DrillType } from "../DrillSelect/types.js";
7
5
  const groupMenuItemMessages = defineMessages({
8
6
  drillDown: { id: "drill_modal_picker.drill-down" },
@@ -13,7 +11,6 @@ const groupMenuItemMessages = defineMessages({
13
11
  });
14
12
  export const useDrillSelectDropdownMenuItems = ({ drillDownItems, drillItems, crossFilteringItems, keyDriverAnalysisItems, drillToUrlItems, onSelect, }) => {
15
13
  const { formatMessage } = useIntl();
16
- const enableImplicitDrillToUrl = useDashboardSelector(selectEnableImplicitDrillToUrl);
17
14
  return useMemo(() => {
18
15
  const createMenuGroup = (items, groupId, groupTitle) => ({
19
16
  type: "group",
@@ -45,7 +42,7 @@ export const useDrillSelectDropdownMenuItems = ({ drillDownItems, drillItems, cr
45
42
  const drillDownMenuItems = drillDownItems.length > 0
46
43
  ? [createMenuGroup(drillDownItems, "drill-down", groupMenuItemMessages.drillDown.id)]
47
44
  : [];
48
- const drillToUrlMenuItems = enableImplicitDrillToUrl && drillToUrlItems.length > 0
45
+ const drillToUrlMenuItems = drillToUrlItems.length > 0
49
46
  ? [createMenuGroup(drillToUrlItems, "drill-to-url", groupMenuItemMessages.drillToUrl.id)]
50
47
  : [];
51
48
  const drillMenuItems = drillItems.length > 0
@@ -74,6 +71,5 @@ export const useDrillSelectDropdownMenuItems = ({ drillDownItems, drillItems, cr
74
71
  drillToUrlItems,
75
72
  formatMessage,
76
73
  onSelect,
77
- enableImplicitDrillToUrl,
78
74
  ]);
79
75
  };
@@ -19,18 +19,21 @@ export function DefaultDashboardExportVariables({ renderMode }) {
19
19
  const conf = useDashboardSelector(selectConfig);
20
20
  const dashboardId = useDashboardSelector(selectDashboardId);
21
21
  const dashboardDescriptor = useDashboardSelector(selectDashboardDescriptor);
22
- const { dateFilters, attributeFilters, isError, isLoading } = useDashboardRelatedFilters(run);
22
+ const { dateFilters, attributeFilters, measureValueFilters, isError, isLoading } = useDashboardRelatedFilters(run);
23
23
  const theme = useTheme();
24
24
  if (!run) {
25
25
  return null;
26
26
  }
27
27
  return (_jsxs("div", { className: "gd-dashboard-meta", ...exportData?.root, children: [
28
- _jsx("div", { ...exportData?.id, children: dashboardId }), dashboardDescriptor.title ? _jsx("div", { ...exportData?.title, children: dashboardDescriptor.title }) : null, dashboardDescriptor.description ? (_jsx("div", { ...exportData?.description, children: dashboardDescriptor.description })) : null, dashboardDescriptor.tags && dashboardDescriptor.tags.length > 0 ? (_jsx("div", { ...exportData?.tags?.root, children: dashboardDescriptor.tags.map((tag, i) => (_jsx("span", { ...exportData?.tags?.tag, children: tag }, i))) })) : null, _jsx("div", { ...exportData?.filters?.root, ...exportData?.filters?.rootData(isLoading, isError), children: dateFilters.length > 0 || attributeFilters.length > 0 ? (_jsxs(_Fragment, { children: [dateFilters.map((filter, i) => (_jsxs("div", { ...exportData?.filters?.dateFilter, ...exportData?.filters?.filter.filterData(filter, isLoading, isError), children: [
28
+ _jsx("div", { ...exportData?.id, children: dashboardId }), dashboardDescriptor.title ? _jsx("div", { ...exportData?.title, children: dashboardDescriptor.title }) : null, dashboardDescriptor.description ? (_jsx("div", { ...exportData?.description, children: dashboardDescriptor.description })) : null, dashboardDescriptor.tags && dashboardDescriptor.tags.length > 0 ? (_jsx("div", { ...exportData?.tags?.root, children: dashboardDescriptor.tags.map((tag, i) => (_jsx("span", { ...exportData?.tags?.tag, children: tag }, i))) })) : null, _jsx("div", { ...exportData?.filters?.root, ...exportData?.filters?.rootData(isLoading, isError), children: dateFilters.length > 0 || attributeFilters.length > 0 || measureValueFilters.length > 0 ? (_jsxs(_Fragment, { children: [dateFilters.map((filter, i) => (_jsxs("div", { ...exportData?.filters?.dateFilter, ...exportData?.filters?.filter.filterData(filter, isLoading, isError), children: [
29
29
  _jsx("span", { ...exportData?.filters?.filter.name, children: filter?.title }),
30
30
  " -", " ", _jsx("span", { ...exportData?.filters?.filter.value, children: filter?.subtitle })
31
31
  ] }, i))), attributeFilters.map((filter, i) => (_jsxs("div", { ...exportData?.filters?.attributeFilter, ...exportData?.filters?.filter.filterData(filter, isLoading, isError), children: [
32
32
  _jsx("span", { ...exportData?.filters?.filter.name, children: filter?.title }),
33
33
  " -", " ", _jsx("span", { ...exportData?.filters?.filter.value, children: filter?.subtitle })
34
+ ] }, i))), measureValueFilters.map((filter, i) => (_jsxs("div", { ...exportData?.filters?.measureValueFilter, ...exportData?.filters?.filter.filterData(filter, isLoading, isError), children: [
35
+ _jsx("span", { ...exportData?.filters?.filter.name, children: filter?.title }),
36
+ " -", " ", _jsx("span", { ...exportData?.filters?.filter.value, children: filter?.subtitle })
34
37
  ] }, i)))] })) : null }), user?.fullName ? _jsx("div", { ...exportData?.user, children: user.fullName }) : null, conf.workspaceDescriptor ? (_jsx("div", { ...exportData?.workspace, children: conf.workspaceDescriptor.title })) : null, _jsx(MetaImage, { image: theme?.images?.logo, type: "logo" }), _jsx(MetaImage, { image: theme?.images?.coverImage, type: "cover-image" }), _jsx(Palette, { data: theme?.palette?.complementary })
35
38
  ] }));
36
39
  }
@@ -3,7 +3,7 @@ import { type DashboardAttributeFilterConfigMode, type DashboardDateFilterConfig
3
3
  * @alpha
4
4
  */
5
5
  export type DashboardRelatedFilter = {
6
- type: "attributeFilter" | "dateFilter";
6
+ type: "attributeFilter" | "dateFilter" | "measureValueFilter";
7
7
  all: boolean;
8
8
  id: string;
9
9
  title: string;
@@ -14,6 +14,7 @@ export type DashboardRelatedFilter = {
14
14
  export declare function useDashboardRelatedFilters(run: boolean): {
15
15
  dateFilters: DashboardRelatedFilter[];
16
16
  attributeFilters: DashboardRelatedFilter[];
17
+ measureValueFilters: DashboardRelatedFilter[];
17
18
  isLoading: boolean;
18
19
  isError: boolean;
19
20
  isSuccess: boolean;
@@ -7,6 +7,7 @@ import { selectAttributeFilterConfigsOverrides } from "../../../model/store/tabs
7
7
  import { selectDateFilterConfigOverrides } from "../../../model/store/tabs/dateFilterConfig/dateFilterConfigSelectors.js";
8
8
  import { selectDateFilterConfigsOverrides } from "../../../model/store/tabs/dateFilterConfigs/dateFilterConfigsSelectors.js";
9
9
  import { selectFilterContextFilters } from "../../../model/store/tabs/filterContext/filterContextSelectors.js";
10
+ import { selectMeasureValueFilterConfigsOverrides } from "../../../model/store/tabs/measureValueFilterConfigs/measureValueFilterConfigsSelectors.js";
10
11
  export function useDashboardRelatedFilters(run) {
11
12
  const backend = useBackendStrict();
12
13
  const workspaceId = useWorkspaceStrict();
@@ -14,6 +15,7 @@ export function useDashboardRelatedFilters(run) {
14
15
  const dateFilterConfig = useDashboardSelector(selectDateFilterConfigOverrides);
15
16
  const dateFiltersConfig = useDashboardSelector(selectDateFilterConfigsOverrides);
16
17
  const attributeFiltersConfig = useDashboardSelector(selectAttributeFilterConfigsOverrides);
18
+ const measureValueFiltersConfig = useDashboardSelector(selectMeasureValueFilterConfigsOverrides);
17
19
  const { result, status } = useCancelablePromise({
18
20
  promise: async () => {
19
21
  if (!run) {
@@ -36,6 +38,12 @@ export function useDashboardRelatedFilters(run) {
36
38
  mode: dateFiltersConfig.find((c) => areObjRefsEqual(c.dateDataSet, f?.dataSet))?.config?.mode,
37
39
  };
38
40
  }
41
+ else if (f?.type === "measureValueFilter") {
42
+ return {
43
+ ...f,
44
+ mode: measureValueFiltersConfig.find((c) => c.localIdentifier === f?.id)?.mode,
45
+ };
46
+ }
39
47
  return {
40
48
  ...f,
41
49
  mode: attributeFiltersConfig.find((c) => c.localIdentifier === f?.id)?.mode,
@@ -47,6 +55,7 @@ export function useDashboardRelatedFilters(run) {
47
55
  isSuccess: status === "success",
48
56
  dateFilters: all.filter((f) => f?.type === "dateFilter"),
49
57
  attributeFilters: all.filter((f) => f?.type === "attributeFilter"),
58
+ measureValueFilters: all.filter((f) => f?.type === "measureValueFilter"),
50
59
  };
51
60
  }
52
61
  async function updateLabelElements(backend, workspaceId, attributeFiltersConfig, dashboardFilter) {
@@ -28,7 +28,7 @@ export type CommonExportDataAttributes = {
28
28
  */
29
29
  export type MetaExportDataAttributes = {
30
30
  "data-export-meta-type"?: ExportMetaType;
31
- "data-export-meta-filter-type"?: "date" | "attribute";
31
+ "data-export-meta-filter-type"?: "date" | "attribute" | "measureValue";
32
32
  "data-export-meta-filter-mode"?: "readonly" | "hidden" | "active";
33
33
  "data-export-meta-filter-status"?: "loading" | "loaded" | "error";
34
34
  "data-export-meta-filters-status"?: "loading" | "loaded" | "error";
@@ -57,6 +57,7 @@ export type MetaExportData = {
57
57
  rootData: (isLoading: boolean, isError: boolean) => MetaExportDataAttributes;
58
58
  dateFilter: MetaExportDataAttributes;
59
59
  attributeFilter: MetaExportDataAttributes;
60
+ measureValueFilter: MetaExportDataAttributes;
60
61
  filter: {
61
62
  name: MetaExportDataAttributes;
62
63
  value: MetaExportDataAttributes;
@@ -1,2 +1,2 @@
1
- // (C) 2025 GoodData Corporation
1
+ // (C) 2025-2026 GoodData Corporation
2
2
  export {};
@@ -201,6 +201,10 @@ export const useMetaExportData = () => {
201
201
  "data-export-meta-type": "dashboard-filter",
202
202
  "data-export-meta-filter-type": "attribute",
203
203
  },
204
+ measureValueFilter: {
205
+ "data-export-meta-type": "dashboard-filter",
206
+ "data-export-meta-filter-type": "measureValue",
207
+ },
204
208
  filter: {
205
209
  name: {
206
210
  "data-export-meta-type": "dashboard-filter-name",
@@ -145,6 +145,9 @@ function DefaultDashboardAttributeFilterInner(props) {
145
145
  filterTitle: title,
146
146
  strong: (chunks) => _jsx("strong", { children: chunks }),
147
147
  });
148
+ const filterDependencyIconAriaLabel = intl.formatMessage({
149
+ id: "filter.dependency.icon.aria.label",
150
+ });
148
151
  const CustomTooltipComponent = useMemo(() => {
149
152
  // When text filter FFs are enabled, the attribute filter dropdown header
150
153
  // has its own help icon (AttributeFilterDetailsBubble), so hide this one.
@@ -160,7 +163,7 @@ function DefaultDashboardAttributeFilterInner(props) {
160
163
  return undefined;
161
164
  }, [displayAttributeTooltip, defaultAttributeFilterTitle, attributeDataSet, isOpen, title]);
162
165
  const shouldExtendTitle = !!capabilities.supportsKeepingDependentFiltersSelection && isAttributeFilterDependent;
163
- const titleExtension = shouldExtendTitle ? (_jsx(AttributeFilterDependencyTooltip, { tooltipContent: filterDependencyIconTooltip })) : null;
166
+ const titleExtension = shouldExtendTitle ? (_jsx(AttributeFilterDependencyTooltip, { tooltipContent: filterDependencyIconTooltip, ariaLabel: filterDependencyIconAriaLabel })) : null;
164
167
  return (_jsx(AttributeFilterDropdownButton, { ...props, isDraggable: isDraggable, TooltipContentComponent: CustomTooltipComponent, titleExtension: titleExtension, className: isVirtualAttributeFilter ? "gd-virtual-attribute-filter-dropdown-button" : undefined }));
165
168
  }
166
169
  return DropdownButton;
@@ -120,7 +120,10 @@ export function DefaultDashboardFilterGroup(props) {
120
120
  filterTitle,
121
121
  strong: (chunks) => _jsx("strong", { children: chunks }),
122
122
  });
123
- return _jsx(AttributeFilterDependencyTooltip, { tooltipContent: filterDependencyIconTooltip });
123
+ const filterDependencyIconAriaLabel = intl.formatMessage({
124
+ id: "filter.dependency.icon.aria.label",
125
+ });
126
+ return (_jsx(AttributeFilterDependencyTooltip, { tooltipContent: filterDependencyIconTooltip, ariaLabel: filterDependencyIconAriaLabel }));
124
127
  }, [capabilities.supportsKeepingDependentFiltersSelection, filterDependenciesByLocalId, intl]);
125
128
  return (_jsx(FilterGroup, { title: groupItem.groupConfig.title, filters: itemFilters, getFilterIdentifier: getFilterIdentifier, hasSelectedElements: hasSelectedElements, renderFilter: renderFilter, getTitleExtension: getTitleExtension }));
126
129
  }