@gooddata/sdk-ui-dashboard 11.35.0-alpha.6 → 11.35.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.
- package/esm/__version.d.ts +1 -1
- package/esm/__version.js +1 -1
- package/esm/_staging/dashboard/dashboardFilterContext.js +18 -1
- package/esm/_staging/sharedHooks/useFiltersNamings.d.ts +1 -1
- package/esm/_staging/sharedHooks/useFiltersNamings.js +32 -5
- package/esm/index.d.ts +1 -1
- package/esm/index.js +1 -1
- package/esm/kdaDialog/dialog/hooks/useChangeAnalysis.js +21 -5
- package/esm/kdaDialog/internalTypes.d.ts +6 -1
- package/esm/kdaDialog/providers/Kda.js +4 -1
- package/esm/kdaDialog/providers/KdaState.js +1 -0
- package/esm/kdaDialog/types.d.ts +13 -2
- package/esm/model/commandHandlers/drill/keyDriverAnalysisHandler.js +8 -3
- package/esm/model/store/_infra/generators.d.ts +1 -0
- package/esm/model/store/_infra/generators.js +4 -1
- package/esm/model/store/filtering/dashboardFilterSelectors.d.ts +1 -1
- package/esm/model/store/filtering/dashboardFilterSelectors.js +8 -5
- package/esm/model/store/tabs/filterContext/filterContextReducers.js +2 -2
- package/esm/model/utils/widgetFilters.d.ts +1 -1
- package/esm/model/utils/widgetFilters.js +1 -1
- package/esm/presentation/automationFilters/components/AutomationFiltersSelect.js +8 -2
- package/esm/presentation/automationFilters/components/AutomationMeasureValueFilter.d.ts +10 -0
- package/esm/presentation/automationFilters/components/AutomationMeasureValueFilter.js +66 -0
- package/esm/presentation/automationFilters/components/AutomationMeasureValueFilterContext.d.ts +25 -0
- package/esm/presentation/automationFilters/components/AutomationMeasureValueFilterContext.js +28 -0
- package/esm/presentation/automationFilters/useAutomationFilters.d.ts +4 -1
- package/esm/presentation/automationFilters/useAutomationFilters.js +35 -4
- package/esm/presentation/automationFilters/utils.d.ts +2 -1
- package/esm/presentation/automationFilters/utils.js +34 -5
- package/esm/presentation/filterBar/measureValueFilter/DefaultDashboardMeasureValueFilter.js +8 -42
- package/esm/presentation/filterBar/measureValueFilter/useDashboardMeasureValueFilterData.d.ts +86 -0
- package/esm/presentation/filterBar/measureValueFilter/useDashboardMeasureValueFilterData.js +105 -0
- package/esm/sdk-ui-dashboard.d.ts +17 -6
- package/package.json +20 -20
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
// (C) 2026 GoodData Corporation
|
|
3
|
+
import { createContext, useContext } from "react";
|
|
4
|
+
const AutomationMeasureValueFilterContext = createContext(null);
|
|
5
|
+
/**
|
|
6
|
+
* @internal
|
|
7
|
+
*/
|
|
8
|
+
export const useAutomationMeasureValueFilterContext = () => {
|
|
9
|
+
const context = useContext(AutomationMeasureValueFilterContext);
|
|
10
|
+
if (!context) {
|
|
11
|
+
throw new Error("AutomationMeasureValueFilterContext not found");
|
|
12
|
+
}
|
|
13
|
+
return context;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* @internal
|
|
17
|
+
*/
|
|
18
|
+
export function AutomationMeasureValueFilterProvider({ children, onChange, onDelete, isLocked, filter, deleteAriaLabel, deleteTooltipContent, lockedTooltipContent, }) {
|
|
19
|
+
return (_jsx(AutomationMeasureValueFilterContext.Provider, { value: {
|
|
20
|
+
onChange,
|
|
21
|
+
onDelete,
|
|
22
|
+
isLocked,
|
|
23
|
+
filter,
|
|
24
|
+
deleteAriaLabel,
|
|
25
|
+
deleteTooltipContent,
|
|
26
|
+
lockedTooltipContent,
|
|
27
|
+
}, children: children }));
|
|
28
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type MutableRefObject } from "react";
|
|
2
|
-
import { type FilterContextItem, type ICatalogAttribute, type ICatalogDateDataset, type IDashboardAttributeFilterConfig, type IDashboardDateFilterConfigItem, type ObjRef } from "@gooddata/sdk-model";
|
|
2
|
+
import { type FilterContextItem, type ICatalogAttribute, type ICatalogDateDataset, type ICatalogMeasure, type IDashboardAttributeFilterConfig, type IDashboardDateFilterConfigItem, type ObjRef } from "@gooddata/sdk-model";
|
|
3
3
|
import { type IAutomationFiltersTab } from "../../model/store/filtering/dashboardFilterSelectors.js";
|
|
4
4
|
/**
|
|
5
5
|
* Processed filter data for a single tab, ready for UI rendering.
|
|
@@ -17,6 +17,8 @@ export interface IProcessedAutomationFiltersTab {
|
|
|
17
17
|
attributes: ICatalogAttribute[];
|
|
18
18
|
/** Catalog date datasets available for Add filter dropdown */
|
|
19
19
|
dateDatasets: ICatalogDateDataset[];
|
|
20
|
+
/** Catalog measures available for Add filter dropdown (for re-adding removed MVFs) */
|
|
21
|
+
measures: ICatalogMeasure[];
|
|
20
22
|
/** Non-selected filters (available but not yet selected) */
|
|
21
23
|
nonSelectedFilters: FilterContextItem[];
|
|
22
24
|
/** Attribute filter configs for this tab */
|
|
@@ -39,6 +41,7 @@ export declare const useAutomationFilters: ({ availableFilters, selectedFilters,
|
|
|
39
41
|
visibleFilters: FilterContextItem[];
|
|
40
42
|
attributes: ICatalogAttribute[];
|
|
41
43
|
dateDatasets: ICatalogDateDataset[];
|
|
44
|
+
measures: ICatalogMeasure[];
|
|
42
45
|
attributeConfigs: IDashboardAttributeFilterConfig[];
|
|
43
46
|
dateConfigs: IDashboardDateFilterConfigItem[];
|
|
44
47
|
filterAnnouncement: string;
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
// (C) 2025-2026 GoodData Corporation
|
|
2
2
|
import { useCallback, useMemo, useRef, useState } from "react";
|
|
3
3
|
import { useIntl } from "react-intl";
|
|
4
|
-
import { areObjRefsEqual, dashboardAttributeFilterItemDisplayForm, isDashboardAttributeFilterItem, isDashboardDateFilter, } from "@gooddata/sdk-model";
|
|
4
|
+
import { areObjRefsEqual, dashboardAttributeFilterItemDisplayForm, isDashboardAttributeFilterItem, isDashboardDateFilter, isDashboardMeasureValueFilter, } from "@gooddata/sdk-model";
|
|
5
5
|
import { useDashboardSelector } from "../../model/react/DashboardStoreProvider.js";
|
|
6
|
-
import { selectCatalogAttributes, selectCatalogDateDatasets, } from "../../model/store/catalog/catalogSelectors.js";
|
|
6
|
+
import { selectCatalogAttributes, selectCatalogDateDatasets, selectCatalogMeasures, } from "../../model/store/catalog/catalogSelectors.js";
|
|
7
7
|
import { selectEnableNewScheduledExport } from "../../model/store/config/configSelectors.js";
|
|
8
8
|
import { selectAutomationCommonDateFilterId, selectDashboardLockedFilters, } from "../../model/store/filtering/dashboardFilterSelectors.js";
|
|
9
9
|
import { selectPersistedDashboardFilterContextDateFilterConfig } from "../../model/store/meta/metaSelectors.js";
|
|
10
10
|
import { selectAttributeFilterConfigsOverrides, selectAttributeFilterConfigsOverridesByTab, } from "../../model/store/tabs/attributeFilterConfigs/attributeFilterConfigsSelectors.js";
|
|
11
11
|
import { selectDateFilterConfigOverridesByTab } from "../../model/store/tabs/dateFilterConfig/dateFilterConfigSelectors.js";
|
|
12
12
|
import { selectDateFilterConfigsOverrides, selectDateFilterConfigsOverridesByTab, } from "../../model/store/tabs/dateFilterConfigs/dateFilterConfigsSelectors.js";
|
|
13
|
-
import {
|
|
13
|
+
import { selectMeasureValueFilterConfigsOverrides, selectMeasureValueFilterConfigsOverridesByTab, } from "../../model/store/tabs/measureValueFilterConfigs/measureValueFilterConfigsSelectors.js";
|
|
14
|
+
import { areFiltersMatchedByIdentifier, getCatalogAttributesByFilters, getCatalogDateDatasetsByFilters, getCatalogMeasuresByFilters, getFilterByCatalogItemRef, getFilterLocalIdentifier, getFilterTitle, getNonHiddenFilters, getNonSelectedFilters, } from "./utils.js";
|
|
14
15
|
/**
|
|
15
16
|
* Computes visible filters by removing hidden filters.
|
|
16
17
|
*/
|
|
@@ -29,6 +30,12 @@ function computeAddDropdownAttributes(nonSelectedFilters, context) {
|
|
|
29
30
|
function computeAddDropdownDateDatasets(nonSelectedFilters, context) {
|
|
30
31
|
return getCatalogDateDatasetsByFilters(nonSelectedFilters, context.allDateDatasets, context.dateConfigs);
|
|
31
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* Computes catalog measures available for the Add filter dropdown.
|
|
35
|
+
*/
|
|
36
|
+
function computeAddDropdownMeasures(nonSelectedFilters, context) {
|
|
37
|
+
return getCatalogMeasuresByFilters(nonSelectedFilters, context.allMeasures, context.mvfConfigs);
|
|
38
|
+
}
|
|
32
39
|
/**
|
|
33
40
|
* Logic for handling inner filters component logic.
|
|
34
41
|
*/
|
|
@@ -36,8 +43,10 @@ export const useAutomationFilters = ({ availableFilters, selectedFilters, onFilt
|
|
|
36
43
|
const intl = useIntl();
|
|
37
44
|
const allAttributes = useDashboardSelector(selectCatalogAttributes);
|
|
38
45
|
const allDateDatasets = useDashboardSelector(selectCatalogDateDatasets);
|
|
46
|
+
const allMeasures = useDashboardSelector(selectCatalogMeasures);
|
|
39
47
|
const attributeConfigs = useDashboardSelector(selectAttributeFilterConfigsOverrides);
|
|
40
48
|
const dateConfigs = useDashboardSelector(selectDateFilterConfigsOverrides);
|
|
49
|
+
const mvfConfigs = useDashboardSelector(selectMeasureValueFilterConfigsOverrides);
|
|
41
50
|
const dateFilterConfig = useDashboardSelector(selectPersistedDashboardFilterContextDateFilterConfig);
|
|
42
51
|
const commonDateFilterId = useDashboardSelector(selectAutomationCommonDateFilterId);
|
|
43
52
|
const lockedFilters = useDashboardSelector(selectDashboardLockedFilters);
|
|
@@ -50,15 +59,19 @@ export const useAutomationFilters = ({ availableFilters, selectedFilters, onFilt
|
|
|
50
59
|
const processingContext = useMemo(() => ({
|
|
51
60
|
allAttributes,
|
|
52
61
|
allDateDatasets,
|
|
62
|
+
allMeasures,
|
|
53
63
|
attributeConfigs,
|
|
54
64
|
dateConfigs,
|
|
65
|
+
mvfConfigs,
|
|
55
66
|
isCommonDateFilterHidden,
|
|
56
67
|
disableDateFilters,
|
|
57
68
|
}), [
|
|
58
69
|
allAttributes,
|
|
59
70
|
allDateDatasets,
|
|
71
|
+
allMeasures,
|
|
60
72
|
attributeConfigs,
|
|
61
73
|
dateConfigs,
|
|
74
|
+
mvfConfigs,
|
|
62
75
|
isCommonDateFilterHidden,
|
|
63
76
|
disableDateFilters,
|
|
64
77
|
]);
|
|
@@ -66,6 +79,7 @@ export const useAutomationFilters = ({ availableFilters, selectedFilters, onFilt
|
|
|
66
79
|
const nonSelectedFilters = useMemo(() => getNonSelectedFilters(availableFilters, selectedFilters), [availableFilters, selectedFilters]);
|
|
67
80
|
const attributes = useMemo(() => computeAddDropdownAttributes(nonSelectedFilters, processingContext), [nonSelectedFilters, processingContext]);
|
|
68
81
|
const dateDatasets = useMemo(() => computeAddDropdownDateDatasets(nonSelectedFilters, processingContext), [nonSelectedFilters, processingContext]);
|
|
82
|
+
const measures = useMemo(() => computeAddDropdownMeasures(nonSelectedFilters, processingContext), [nonSelectedFilters, processingContext]);
|
|
69
83
|
const focusAddFilterButton = useCallback(() => {
|
|
70
84
|
//focus add button, use requestAnimationFrame to wait for rerender
|
|
71
85
|
requestAnimationFrame(() => {
|
|
@@ -130,7 +144,11 @@ export const useAutomationFilters = ({ availableFilters, selectedFilters, onFilt
|
|
|
130
144
|
const selectedDateDataSets = dateDatasets.filter((ds) => areObjRefsEqual(ds.dataSet.ref, catalogItemRef));
|
|
131
145
|
const attributeFilter = selectedAttributeDisplayForms.reduce((acc, displayFormRef) => acc || getFilterByCatalogItemRef(displayFormRef, nonSelectedFilters), undefined);
|
|
132
146
|
const dateFilter = selectedDateDataSets.reduce((acc, dateDataSet) => acc || getFilterByCatalogItemRef(dateDataSet.dataSet.ref, nonSelectedFilters), undefined);
|
|
133
|
-
|
|
147
|
+
// For MVF: the dropdown emits the metric's catalog ref directly; look it up by ref.
|
|
148
|
+
const measureFilter = getFilterByCatalogItemRef(catalogItemRef, nonSelectedFilters);
|
|
149
|
+
const filter = attributeFilter ||
|
|
150
|
+
dateFilter ||
|
|
151
|
+
(measureFilter && isDashboardMeasureValueFilter(measureFilter) ? measureFilter : undefined);
|
|
134
152
|
if (filter) {
|
|
135
153
|
const filterTitle = getFilterTitle(filter, allAttributes, allDateDatasets, intl);
|
|
136
154
|
const message = intl.formatMessage({ id: "automationFilters.announcement.filterAdded" }, { title: filterTitle });
|
|
@@ -166,6 +184,7 @@ export const useAutomationFilters = ({ availableFilters, selectedFilters, onFilt
|
|
|
166
184
|
visibleFilters,
|
|
167
185
|
attributes,
|
|
168
186
|
dateDatasets,
|
|
187
|
+
measures,
|
|
169
188
|
attributeConfigs,
|
|
170
189
|
dateConfigs,
|
|
171
190
|
filterAnnouncement,
|
|
@@ -186,6 +205,7 @@ export const useAutomationFilters = ({ availableFilters, selectedFilters, onFilt
|
|
|
186
205
|
export const useAutomationFiltersByTab = ({ filtersByTab, editedFiltersByTab, onFiltersByTabChange, onStoreFiltersChange, disableDateFilters = false, }) => {
|
|
187
206
|
const allAttributes = useDashboardSelector(selectCatalogAttributes);
|
|
188
207
|
const allDateDatasets = useDashboardSelector(selectCatalogDateDatasets);
|
|
208
|
+
const allMeasures = useDashboardSelector(selectCatalogMeasures);
|
|
189
209
|
const commonDateFilterId = useDashboardSelector(selectAutomationCommonDateFilterId);
|
|
190
210
|
const [filterAnnouncement] = useState("");
|
|
191
211
|
const addFilterButtonRef = useRef(null);
|
|
@@ -194,6 +214,7 @@ export const useAutomationFiltersByTab = ({ filtersByTab, editedFiltersByTab, on
|
|
|
194
214
|
const attributeConfigsByTab = useDashboardSelector(selectAttributeFilterConfigsOverridesByTab);
|
|
195
215
|
const dateConfigsByTab = useDashboardSelector(selectDateFilterConfigsOverridesByTab);
|
|
196
216
|
const dateFilterConfigByTab = useDashboardSelector(selectDateFilterConfigOverridesByTab);
|
|
217
|
+
const mvfConfigsByTab = useDashboardSelector(selectMeasureValueFilterConfigsOverridesByTab);
|
|
197
218
|
const processedFiltersByTab = useMemo(() => {
|
|
198
219
|
if (!filtersByTab || filtersByTab.length === 0) {
|
|
199
220
|
return undefined;
|
|
@@ -203,14 +224,17 @@ export const useAutomationFiltersByTab = ({ filtersByTab, editedFiltersByTab, on
|
|
|
203
224
|
// Get configs specific to this tab
|
|
204
225
|
const attributeConfigs = attributeConfigsByTab[tabId] ?? [];
|
|
205
226
|
const dateConfigs = dateConfigsByTab[tabId] ?? [];
|
|
227
|
+
const mvfConfigs = mvfConfigsByTab[tabId] ?? [];
|
|
206
228
|
const dateFilterConfig = dateFilterConfigByTab[tabId];
|
|
207
229
|
const isCommonDateFilterHidden = dateFilterConfig?.mode === "hidden";
|
|
208
230
|
// Create processing context for this specific tab
|
|
209
231
|
const processingContext = {
|
|
210
232
|
allAttributes,
|
|
211
233
|
allDateDatasets,
|
|
234
|
+
allMeasures,
|
|
212
235
|
attributeConfigs,
|
|
213
236
|
dateConfigs,
|
|
237
|
+
mvfConfigs,
|
|
214
238
|
isCommonDateFilterHidden,
|
|
215
239
|
disableDateFilters,
|
|
216
240
|
};
|
|
@@ -224,6 +248,7 @@ export const useAutomationFiltersByTab = ({ filtersByTab, editedFiltersByTab, on
|
|
|
224
248
|
// Compute catalog items for Add dropdown
|
|
225
249
|
const attributes = computeAddDropdownAttributes(nonSelectedFilters, processingContext);
|
|
226
250
|
const dateDatasets = computeAddDropdownDateDatasets(nonSelectedFilters, processingContext);
|
|
251
|
+
const measures = computeAddDropdownMeasures(nonSelectedFilters, processingContext);
|
|
227
252
|
return {
|
|
228
253
|
tabId: tab.tabId,
|
|
229
254
|
tabTitle: tab.tabTitle,
|
|
@@ -231,6 +256,7 @@ export const useAutomationFiltersByTab = ({ filtersByTab, editedFiltersByTab, on
|
|
|
231
256
|
lockedFilters: tab.lockedFilters,
|
|
232
257
|
attributes,
|
|
233
258
|
dateDatasets,
|
|
259
|
+
measures,
|
|
234
260
|
nonSelectedFilters,
|
|
235
261
|
attributeConfigs,
|
|
236
262
|
dateConfigs,
|
|
@@ -241,9 +267,11 @@ export const useAutomationFiltersByTab = ({ filtersByTab, editedFiltersByTab, on
|
|
|
241
267
|
editedFiltersByTab,
|
|
242
268
|
allAttributes,
|
|
243
269
|
allDateDatasets,
|
|
270
|
+
allMeasures,
|
|
244
271
|
attributeConfigsByTab,
|
|
245
272
|
dateConfigsByTab,
|
|
246
273
|
dateFilterConfigByTab,
|
|
274
|
+
mvfConfigsByTab,
|
|
247
275
|
disableDateFilters,
|
|
248
276
|
]);
|
|
249
277
|
// Handlers for per-tab filter operations (similar to original hook)
|
|
@@ -303,6 +331,9 @@ export const useAutomationFiltersByTab = ({ filtersByTab, editedFiltersByTab, on
|
|
|
303
331
|
else if (isDashboardDateFilter(f)) {
|
|
304
332
|
return selectedDateDataSets.some((ds) => areObjRefsEqual(f.dateFilter.dataSet, ds.dataSet.ref));
|
|
305
333
|
}
|
|
334
|
+
else if (isDashboardMeasureValueFilter(f)) {
|
|
335
|
+
return areObjRefsEqual(f.dashboardMeasureValueFilter.measure, displayForm);
|
|
336
|
+
}
|
|
306
337
|
return false;
|
|
307
338
|
});
|
|
308
339
|
if (availableFilter) {
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { type IntlShape } from "react-intl";
|
|
2
|
-
import { type FilterContextItem, type IAutomationVisibleFilter, type ICatalogAttribute, type ICatalogDateDataset, type IDashboardAttributeFilterConfig, type IDashboardDateFilterConfigItem, type IDateFilter, type IFilter, type IInsight, type ObjRef } from "@gooddata/sdk-model";
|
|
2
|
+
import { type FilterContextItem, type IAutomationVisibleFilter, type ICatalogAttribute, type ICatalogDateDataset, type ICatalogMeasure, type IDashboardAttributeFilterConfig, type IDashboardDateFilterConfigItem, type IDashboardMeasureValueFilterConfig, type IDateFilter, type IFilter, type IInsight, type ObjRef } from "@gooddata/sdk-model";
|
|
3
3
|
import type { ExtendedDashboardWidget } from "../../model/types/layoutTypes.js";
|
|
4
4
|
export declare const getFilterLocalIdentifier: (filter: FilterContextItem) => string | undefined;
|
|
5
5
|
export declare const validateAllFilterLocalIdentifiers: (filters: FilterContextItem[]) => boolean;
|
|
6
6
|
export declare const areFiltersMatchedByIdentifier: (filter1: FilterContextItem, filter2: FilterContextItem) => boolean;
|
|
7
7
|
export declare const getNonSelectedFilters: (allFilters: FilterContextItem[], selectedFilters: FilterContextItem[]) => FilterContextItem[];
|
|
8
8
|
export declare const getCatalogAttributesByFilters: (filters: FilterContextItem[], attributes: ICatalogAttribute[], attributeConfigs: IDashboardAttributeFilterConfig[]) => ICatalogAttribute[];
|
|
9
|
+
export declare const getCatalogMeasuresByFilters: (filters: FilterContextItem[], measures: ICatalogMeasure[], mvfConfigs: IDashboardMeasureValueFilterConfig[]) => ICatalogMeasure[];
|
|
9
10
|
export declare const getCatalogDateDatasetsByFilters: (filters: FilterContextItem[], dateDataset: ICatalogDateDataset[], dateConfigs: IDashboardDateFilterConfigItem[]) => ICatalogDateDataset[];
|
|
10
11
|
export declare const getFilterByCatalogItemRef: (ref: ObjRef, filters: FilterContextItem[]) => FilterContextItem | undefined;
|
|
11
12
|
export declare const getVisibleFiltersByFilters: (selectedFilters: FilterContextItem[] | undefined, visibleFiltersMetadata: IAutomationVisibleFilter[] | undefined, storeFilters?: boolean | undefined) => IAutomationVisibleFilter[] | undefined;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// (C) 2025-2026 GoodData Corporation
|
|
2
2
|
import { compact, isEqual } from "lodash-es";
|
|
3
|
-
import { absoluteDateFilterValues, areObjRefsEqual, attributeLocalId, dashboardAttributeFilterItemDisplayForm, dashboardAttributeFilterItemLocalIdentifier, dashboardFilterLocalIdentifier, dashboardFilterObjRef, filterAttributeElements, filterLocalIdentifier, filterObjRef, getAttributeElementsItems, insightAttributes, isAbsoluteDateFilter, isAllTimeDateFilter, isAllValuesAttributeFilter, isAllValuesDashboardAttributeFilter, isArbitraryAttributeFilter, isAttributeFilter, isDashboardArbitraryAttributeFilter, isDashboardAttributeFilter, isDashboardAttributeFilterItem, isDashboardCommonDateFilter, isDashboardDateFilter, isDashboardMatchAttributeFilter, isDashboardMeasureValueFilter, isDateFilter, isInsightWidget, isLocalIdRef, isMatchAttributeFilter, isMeasureValueFilter, isNegativeAttributeFilter, isNoopAllTimeDashboardDateFilter, isPositiveAttributeFilter, isRelativeDateFilter, mergeFilters, relativeDateFilterValues, } from "@gooddata/sdk-model";
|
|
3
|
+
import { absoluteDateFilterValues, areObjRefsEqual, attributeLocalId, dashboardAttributeFilterItemDisplayForm, dashboardAttributeFilterItemLocalIdentifier, dashboardFilterLocalIdentifier, dashboardFilterObjRef, filterAttributeElements, filterLocalIdentifier, filterObjRef, getAttributeElementsItems, hasMeasureValueFilterConditions, insightAttributes, isAbsoluteDateFilter, isAllDashboardMeasureValueFilter, isAllTimeDateFilter, isAllValuesAttributeFilter, isAllValuesDashboardAttributeFilter, isArbitraryAttributeFilter, isAttributeFilter, isDashboardArbitraryAttributeFilter, isDashboardAttributeFilter, isDashboardAttributeFilterItem, isDashboardCommonDateFilter, isDashboardDateFilter, isDashboardMatchAttributeFilter, isDashboardMeasureValueFilter, isDateFilter, isInsightWidget, isLocalIdRef, isMatchAttributeFilter, isMeasureValueFilter, isNegativeAttributeFilter, isNoopAllTimeDashboardDateFilter, isPositiveAttributeFilter, isRelativeDateFilter, mergeFilters, relativeDateFilterValues, } from "@gooddata/sdk-model";
|
|
4
4
|
import { filterContextItemsToDashboardFiltersByWidget } from "../../converters/filterConverters.js";
|
|
5
5
|
import { removeIgnoredWidgetFilters } from "../../model/utils/widgetFilters.js";
|
|
6
6
|
export const getFilterLocalIdentifier = (filter) => {
|
|
@@ -38,6 +38,21 @@ export const getCatalogAttributesByFilters = (filters, attributes, attributeConf
|
|
|
38
38
|
});
|
|
39
39
|
});
|
|
40
40
|
};
|
|
41
|
+
export const getCatalogMeasuresByFilters = (filters, measures, mvfConfigs) => {
|
|
42
|
+
const ignoredLocalIdentifiers = mvfConfigs
|
|
43
|
+
.filter((config) => config.mode === "hidden")
|
|
44
|
+
.map((config) => config.localIdentifier);
|
|
45
|
+
return measures.filter((measure) => {
|
|
46
|
+
return filters.some((filter) => {
|
|
47
|
+
if (isDashboardMeasureValueFilter(filter)) {
|
|
48
|
+
const localIdentifier = filter.dashboardMeasureValueFilter.localIdentifier;
|
|
49
|
+
return (!ignoredLocalIdentifiers.includes(localIdentifier) &&
|
|
50
|
+
areObjRefsEqual(filter.dashboardMeasureValueFilter.measure, measure.measure.ref));
|
|
51
|
+
}
|
|
52
|
+
return false;
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
};
|
|
41
56
|
export const getCatalogDateDatasetsByFilters = (filters, dateDataset, dateConfigs) => {
|
|
42
57
|
const ignoredDateDatasets = dateConfigs
|
|
43
58
|
.filter((config) => {
|
|
@@ -61,6 +76,9 @@ export const getFilterByCatalogItemRef = (ref, filters) => {
|
|
|
61
76
|
else if (isDashboardDateFilter(filter)) {
|
|
62
77
|
return areObjRefsEqual(filter.dateFilter.dataSet, ref);
|
|
63
78
|
}
|
|
79
|
+
else if (isDashboardMeasureValueFilter(filter)) {
|
|
80
|
+
return areObjRefsEqual(filter.dashboardMeasureValueFilter.measure, ref);
|
|
81
|
+
}
|
|
64
82
|
return false;
|
|
65
83
|
});
|
|
66
84
|
};
|
|
@@ -69,9 +87,9 @@ export const getVisibleFiltersByFilters = (selectedFilters, visibleFiltersMetada
|
|
|
69
87
|
return undefined;
|
|
70
88
|
}
|
|
71
89
|
const filters = (selectedFilters ?? [])
|
|
72
|
-
// Strip noop "All values" attribute filters
|
|
73
|
-
// and should not be stored in visible filters metadata.
|
|
74
|
-
.filter((filter) => !isAllValuesDashboardAttributeFilter(filter))
|
|
90
|
+
// Strip noop "All values" attribute filters and "All" measure value filters —
|
|
91
|
+
// they have no effect on execution and should not be stored in visible filters metadata.
|
|
92
|
+
.filter((filter) => !isAllValuesDashboardAttributeFilter(filter) && !isAllDashboardMeasureValueFilter(filter))
|
|
75
93
|
.map((selectedFilter) => {
|
|
76
94
|
const selectedLocalIdentifier = getFilterLocalIdentifier(selectedFilter);
|
|
77
95
|
const targetFilter = (visibleFiltersMetadata ?? []).find((visibleFilter) => {
|
|
@@ -176,6 +194,10 @@ export const getAppliedWidgetFilters = (selectedAutomationFilters, dashboardHidd
|
|
|
176
194
|
if (isDateFilter(filter)) {
|
|
177
195
|
return !isNoopAllTimeDateFilterFixed(filter);
|
|
178
196
|
}
|
|
197
|
+
// Strip noop "All" measure value filters (no conditions).
|
|
198
|
+
if (isMeasureValueFilter(filter)) {
|
|
199
|
+
return hasMeasureValueFilterConditions(filter);
|
|
200
|
+
}
|
|
179
201
|
// Strip noop "All values" attribute filters (negative filter with empty exclusion list).
|
|
180
202
|
return !isAllValuesAttributeFilter(filter);
|
|
181
203
|
});
|
|
@@ -196,7 +218,11 @@ export const getAppliedDashboardFilters = (selectedAutomationFilters, dashboardH
|
|
|
196
218
|
if (isDashboardDateFilter(filter)) {
|
|
197
219
|
return !isNoopAllTimeDashboardDateFilter(filter);
|
|
198
220
|
}
|
|
199
|
-
// Strip noop "All
|
|
221
|
+
// Strip noop "All" measure value filters (no/empty conditions).
|
|
222
|
+
if (isDashboardMeasureValueFilter(filter)) {
|
|
223
|
+
return !isAllDashboardMeasureValueFilter(filter);
|
|
224
|
+
}
|
|
225
|
+
// Strip noop "All values" attribute filters.
|
|
200
226
|
return !isAllValuesDashboardAttributeFilter(filter);
|
|
201
227
|
});
|
|
202
228
|
};
|
|
@@ -373,5 +399,8 @@ export const getFilterTitle = (filter, allAttributes, allDateDatasets, intl) =>
|
|
|
373
399
|
const dateDataset = allDateDatasets.find((ds) => areObjRefsEqual(ds.dataSet.ref, filter.dateFilter.dataSet));
|
|
374
400
|
return dateDataset?.dataSet.title || "";
|
|
375
401
|
}
|
|
402
|
+
if (isDashboardMeasureValueFilter(filter)) {
|
|
403
|
+
return filter.dashboardMeasureValueFilter.title || "";
|
|
404
|
+
}
|
|
376
405
|
return "";
|
|
377
406
|
};
|
|
@@ -3,16 +3,15 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import { useCallback, useMemo, useRef, useState } from "react";
|
|
4
4
|
import cx from "classnames";
|
|
5
5
|
import { useIntl } from "react-intl";
|
|
6
|
-
import { DashboardAttributeFilterConfigModeValues,
|
|
7
|
-
import { MeasureValueFilter,
|
|
6
|
+
import { DashboardAttributeFilterConfigModeValues, } from "@gooddata/sdk-model";
|
|
7
|
+
import { MeasureValueFilter, } from "@gooddata/sdk-ui-filters";
|
|
8
8
|
import { Bubble, BubbleHoverTrigger, UiControlButton } from "@gooddata/sdk-ui-kit";
|
|
9
9
|
import { setDashboardMeasureValueFilterConfigMode } from "../../../model/commands/dashboard.js";
|
|
10
10
|
import { setMeasureValueFilterTitle } from "../../../model/commands/filters.js";
|
|
11
11
|
import { useDashboardSelector } from "../../../model/react/DashboardStoreProvider.js";
|
|
12
12
|
import { useDashboardCommandProcessing } from "../../../model/react/useDashboardCommandProcessing.js";
|
|
13
13
|
import { selectBackendCapabilities } from "../../../model/store/backendCapabilities/backendCapabilitiesSelectors.js";
|
|
14
|
-
import {
|
|
15
|
-
import { selectIsApplyFiltersAllAtOnceEnabledAndSet, selectLocale, selectSeparators, } from "../../../model/store/config/configSelectors.js";
|
|
14
|
+
import { selectIsApplyFiltersAllAtOnceEnabledAndSet } from "../../../model/store/config/configSelectors.js";
|
|
16
15
|
import { selectIsInEditMode } from "../../../model/store/renderMode/renderModeSelectors.js";
|
|
17
16
|
import { selectWorkingFilterContextMeasureValueFilterByLocalId } from "../../../model/store/tabs/filterContext/filterContextSelectors.js";
|
|
18
17
|
import { selectMeasureValueFilterConfigsModeMap } from "../../../model/store/tabs/measureValueFilterConfigs/measureValueFilterConfigsSelectors.js";
|
|
@@ -20,22 +19,8 @@ import { useAttributeFilterConfigTexts } from "../attributeFilter/useAttributeFi
|
|
|
20
19
|
import { getVisibilityIcon } from "../utils.js";
|
|
21
20
|
import { CustomConfigureMeasureValueFilterDropdownActions, CustomMeasureValueFilterDropdownActions, } from "./CustomDropdownActions.js";
|
|
22
21
|
import { MeasureValueFilterConfiguration } from "./MeasureValueFilterConfiguration.js";
|
|
23
|
-
|
|
22
|
+
import { getSharedDashboardMvfProps, normalizeMeasureValueFilterConditions, useDashboardMeasureValueFilterData, } from "./useDashboardMeasureValueFilterData.js";
|
|
24
23
|
const DEFAULT_VISIBILITY_BUBBLE_ALIGN_POINTS = [{ align: "bc tl", offset: { x: 0, y: 5 } }];
|
|
25
|
-
function isPercentageFormat(format) {
|
|
26
|
-
return !!format && PERCENT_FORMAT_REGEX.test(format);
|
|
27
|
-
}
|
|
28
|
-
function findCatalogMetric(measure, measures) {
|
|
29
|
-
return measures.find((m) => areObjRefsEqual(m.measure.ref, measure));
|
|
30
|
-
}
|
|
31
|
-
function normalizeMeasureValueFilterConditions(updated) {
|
|
32
|
-
const body = updated?.measureValueFilter;
|
|
33
|
-
return body?.conditions && body.conditions.length > 0
|
|
34
|
-
? body.conditions
|
|
35
|
-
: body?.condition
|
|
36
|
-
? [body.condition]
|
|
37
|
-
: undefined;
|
|
38
|
-
}
|
|
39
24
|
function MeasureValueFilterVisibilityIcon({ visibilityIcon, disabled, }) {
|
|
40
25
|
if (!visibilityIcon) {
|
|
41
26
|
return null;
|
|
@@ -53,23 +38,15 @@ function MeasureValueFilterVisibilityIcon({ visibilityIcon, disabled, }) {
|
|
|
53
38
|
export function DefaultDashboardMeasureValueFilter(props) {
|
|
54
39
|
const { filter, readonly, autoOpen, onMeasureValueFilterChanged, onMeasureValueFilterClose } = props;
|
|
55
40
|
const intl = useIntl();
|
|
56
|
-
const measures = useDashboardSelector(selectCatalogMeasures);
|
|
57
|
-
const separators = useDashboardSelector(selectSeparators);
|
|
58
|
-
const locale = useDashboardSelector(selectLocale);
|
|
59
41
|
const isEditMode = useDashboardSelector(selectIsInEditMode);
|
|
60
42
|
const isApplyAllAtOnceEnabledAndSet = useDashboardSelector(selectIsApplyFiltersAllAtOnceEnabledAndSet);
|
|
61
43
|
const capabilities = useDashboardSelector(selectBackendCapabilities);
|
|
62
44
|
const measureValueFilterConfigsModeMap = useDashboardSelector(selectMeasureValueFilterConfigsModeMap);
|
|
63
45
|
const { cancelText, closeText, saveText, applyText, titleText, resetTitleText, modeCategoryTitleText } = useAttributeFilterConfigTexts();
|
|
64
|
-
const
|
|
65
|
-
const workingFilter = useDashboardSelector(selectWorkingFilterContextMeasureValueFilterByLocalId(localIdentifier));
|
|
46
|
+
const workingFilter = useDashboardSelector(selectWorkingFilterContextMeasureValueFilterByLocalId(filter.dashboardMeasureValueFilter.localIdentifier));
|
|
66
47
|
const filterToDisplay = isApplyAllAtOnceEnabledAndSet ? (workingFilter ?? filter) : filter;
|
|
67
|
-
const
|
|
68
|
-
const
|
|
69
|
-
const defaultMetricTitle = catalogMetric?.measure.title ?? objRefToString(measure);
|
|
70
|
-
const metricTitle = customTitle ?? defaultMetricTitle;
|
|
71
|
-
const format = catalogMetric?.measure.format;
|
|
72
|
-
const usePercentage = isPercentageFormat(format);
|
|
48
|
+
const mvfData = useDashboardMeasureValueFilterData(filter, filterToDisplay);
|
|
49
|
+
const { localIdentifier, customTitle, defaultMetricTitle, metricTitle, conditionLabel } = mvfData;
|
|
73
50
|
const mode = measureValueFilterConfigsModeMap.get(localIdentifier) ??
|
|
74
51
|
DashboardAttributeFilterConfigModeValues.ACTIVE;
|
|
75
52
|
const visibilityIcon = getVisibilityIcon(mode, isEditMode, !!capabilities.supportsHiddenAndLockedFiltersOnUI, intl);
|
|
@@ -86,17 +63,6 @@ export function DefaultDashboardMeasureValueFilter(props) {
|
|
|
86
63
|
successEvent: "GDC.DASH/EVT.MEASURE_VALUE_FILTER_CONFIG.MODE_CHANGED",
|
|
87
64
|
errorEvent: "GDC.DASH/EVT.COMMAND.FAILED",
|
|
88
65
|
});
|
|
89
|
-
const conditionLabel = useMemo(() => getMeasureValueFilterConditionLabel(intl, conditions, {
|
|
90
|
-
usePercentage,
|
|
91
|
-
separators,
|
|
92
|
-
}), [intl, conditions, usePercentage, separators]);
|
|
93
|
-
const dropdownFilter = useMemo(() => ({
|
|
94
|
-
measureValueFilter: {
|
|
95
|
-
measure,
|
|
96
|
-
localIdentifier,
|
|
97
|
-
...(conditions && conditions.length > 0 ? { conditions } : {}),
|
|
98
|
-
},
|
|
99
|
-
}), [measure, localIdentifier, conditions]);
|
|
100
66
|
const handleClose = useCallback(() => {
|
|
101
67
|
setIsConfigurationOpen(false);
|
|
102
68
|
onMeasureValueFilterClose?.();
|
|
@@ -189,5 +155,5 @@ export function DefaultDashboardMeasureValueFilter(props) {
|
|
|
189
155
|
}
|
|
190
156
|
return DashboardMeasureValueFilterDropdownButton;
|
|
191
157
|
}, [conditionLabel, intl, isEditMode, readonly, visibilityIcon]);
|
|
192
|
-
return (_jsx(MeasureValueFilter, { onApply: handleApply, onChange: isApplyAllAtOnceEnabledAndSet ? handleChange : undefined, withoutApply: isApplyAllAtOnceEnabledAndSet, BodyComponent: BodyComponent, DropdownActionsComponent: DropdownActionsComponent, DropdownButtonComponent: DropdownButtonComponent, onCancel: handleClose,
|
|
158
|
+
return (_jsx(MeasureValueFilter, { ...getSharedDashboardMvfProps(mvfData), onApply: handleApply, onChange: isApplyAllAtOnceEnabledAndSet ? handleChange : undefined, withoutApply: isApplyAllAtOnceEnabledAndSet, BodyComponent: BodyComponent, DropdownActionsComponent: DropdownActionsComponent, DropdownButtonComponent: DropdownButtonComponent, onCancel: handleClose, autoOpen: autoOpen }));
|
|
193
159
|
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { type IntlShape } from "react-intl";
|
|
2
|
+
import { type ICatalogMeasure, type IDashboardMeasureValueFilter, type IMeasureValueFilter, type ISeparators, type MeasureValueFilterCondition, type ObjRef } from "@gooddata/sdk-model";
|
|
3
|
+
/**
|
|
4
|
+
* Normalizes the output of the SDK `<MeasureValueFilter />` onApply callback into a single
|
|
5
|
+
* `conditions` array. The SDK can return either `condition` (single comparison/range) or
|
|
6
|
+
* `conditions` (multi-condition OR); the dashboard model only uses `conditions`. Returns
|
|
7
|
+
* undefined when the filter is "All" (no condition selected).
|
|
8
|
+
*
|
|
9
|
+
* @internal
|
|
10
|
+
*/
|
|
11
|
+
export declare function normalizeMeasureValueFilterConditions(updated: IMeasureValueFilter | null): MeasureValueFilterCondition[] | undefined;
|
|
12
|
+
/**
|
|
13
|
+
* Derived data shared by every dashboard MVF host (filter bar, automation/scheduling dialog,
|
|
14
|
+
* any future location). Resolves the catalog metric, computes title/format/percentage/conditions,
|
|
15
|
+
* builds the execution-level MVF shape the SDK dropdown expects, and produces the condition
|
|
16
|
+
* label shown on the chip.
|
|
17
|
+
*
|
|
18
|
+
* @internal
|
|
19
|
+
*/
|
|
20
|
+
export interface IDashboardMeasureValueFilterData {
|
|
21
|
+
measure: ObjRef;
|
|
22
|
+
localIdentifier: string;
|
|
23
|
+
/** Custom title from the filter, if any. */
|
|
24
|
+
customTitle: string | undefined;
|
|
25
|
+
/** Catalog metric the filter references; undefined if not in the catalog. */
|
|
26
|
+
catalogMetric: ICatalogMeasure | undefined;
|
|
27
|
+
/** Title fallback when no custom title is set. */
|
|
28
|
+
defaultMetricTitle: string;
|
|
29
|
+
/** Effective title — custom title or catalog title or stringified objRef. */
|
|
30
|
+
metricTitle: string;
|
|
31
|
+
/** Catalog metric format pattern, if any. */
|
|
32
|
+
format: string | undefined;
|
|
33
|
+
/** Whether the format expresses a percentage. */
|
|
34
|
+
usePercentage: boolean;
|
|
35
|
+
/** Conditions from the (possibly working) filter the UI should reflect. */
|
|
36
|
+
conditions: MeasureValueFilterCondition[] | undefined;
|
|
37
|
+
/** Human-readable condition summary shown on the chip ("> 100 OR ≥ 50%"). */
|
|
38
|
+
conditionLabel: string;
|
|
39
|
+
/** Execution-level MVF that the SDK <MeasureValueFilter /> takes as `filter`. */
|
|
40
|
+
dropdownFilter: IMeasureValueFilter;
|
|
41
|
+
separators: ISeparators;
|
|
42
|
+
locale: string;
|
|
43
|
+
intl: IntlShape;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Hook that resolves the shared data needed to render a dashboard MVF dropdown.
|
|
47
|
+
*
|
|
48
|
+
* The host owns the choice of which filter to reflect in the UI: the persisted filter
|
|
49
|
+
* (`filter`), or the working/staged filter when "Apply together" mode is active. Pass
|
|
50
|
+
* the chosen one as `filterToDisplay`; if omitted, `filter` itself is used.
|
|
51
|
+
*
|
|
52
|
+
* @internal
|
|
53
|
+
*/
|
|
54
|
+
export declare function useDashboardMeasureValueFilterData(filter: IDashboardMeasureValueFilter, filterToDisplay?: IDashboardMeasureValueFilter): IDashboardMeasureValueFilterData;
|
|
55
|
+
/**
|
|
56
|
+
* Props that every dashboard MVF host passes to the SDK `<MeasureValueFilter />` unchanged.
|
|
57
|
+
* Host-specific bits — `DropdownButtonComponent`, `onApply`, `onChange`, `onCancel`,
|
|
58
|
+
* `withoutApply`, `BodyComponent`, `DropdownActionsComponent`, `autoOpen` — are added
|
|
59
|
+
* by the host on top of this bundle.
|
|
60
|
+
*
|
|
61
|
+
* @internal
|
|
62
|
+
*/
|
|
63
|
+
export interface ISharedDashboardMvfProps {
|
|
64
|
+
filter: IMeasureValueFilter;
|
|
65
|
+
measureIdentifier: string;
|
|
66
|
+
buttonTitle: string;
|
|
67
|
+
measureTitle: string;
|
|
68
|
+
usePercentage: boolean;
|
|
69
|
+
format: string | undefined;
|
|
70
|
+
useShortFormat: true;
|
|
71
|
+
displayTreatNullAsZeroOption: true;
|
|
72
|
+
separators: ISeparators;
|
|
73
|
+
locale: string;
|
|
74
|
+
enableOperatorSelection: true;
|
|
75
|
+
enableMultipleConditions: true;
|
|
76
|
+
isDimensionalityEnabled: false;
|
|
77
|
+
isFilterSummaryEnabled: true;
|
|
78
|
+
isHeaderEnabled: true;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Build the shared `<MeasureValueFilter />` prop bundle from the data hook output.
|
|
82
|
+
* Spread this into the SDK component and add host-specific props after.
|
|
83
|
+
*
|
|
84
|
+
* @internal
|
|
85
|
+
*/
|
|
86
|
+
export declare function getSharedDashboardMvfProps(data: IDashboardMeasureValueFilterData): ISharedDashboardMvfProps;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
// (C) 2026 GoodData Corporation
|
|
2
|
+
import { useMemo } from "react";
|
|
3
|
+
import { useIntl } from "react-intl";
|
|
4
|
+
import { areObjRefsEqual, objRefToString, } from "@gooddata/sdk-model";
|
|
5
|
+
import { getMeasureValueFilterConditionLabel } from "@gooddata/sdk-ui-filters";
|
|
6
|
+
import { useDashboardSelector } from "../../../model/react/DashboardStoreProvider.js";
|
|
7
|
+
import { selectCatalogMeasures } from "../../../model/store/catalog/catalogSelectors.js";
|
|
8
|
+
import { selectLocale, selectSeparators } from "../../../model/store/config/configSelectors.js";
|
|
9
|
+
const PERCENT_FORMAT_REGEX = /%/;
|
|
10
|
+
function isPercentageFormat(format) {
|
|
11
|
+
return !!format && PERCENT_FORMAT_REGEX.test(format);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Normalizes the output of the SDK `<MeasureValueFilter />` onApply callback into a single
|
|
15
|
+
* `conditions` array. The SDK can return either `condition` (single comparison/range) or
|
|
16
|
+
* `conditions` (multi-condition OR); the dashboard model only uses `conditions`. Returns
|
|
17
|
+
* undefined when the filter is "All" (no condition selected).
|
|
18
|
+
*
|
|
19
|
+
* @internal
|
|
20
|
+
*/
|
|
21
|
+
export function normalizeMeasureValueFilterConditions(updated) {
|
|
22
|
+
const body = updated?.measureValueFilter;
|
|
23
|
+
if (body?.conditions && body.conditions.length > 0) {
|
|
24
|
+
return body.conditions;
|
|
25
|
+
}
|
|
26
|
+
if (body?.condition) {
|
|
27
|
+
return [body.condition];
|
|
28
|
+
}
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
function findCatalogMetric(measure, measures) {
|
|
32
|
+
return measures.find((m) => areObjRefsEqual(m.measure.ref, measure));
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Hook that resolves the shared data needed to render a dashboard MVF dropdown.
|
|
36
|
+
*
|
|
37
|
+
* The host owns the choice of which filter to reflect in the UI: the persisted filter
|
|
38
|
+
* (`filter`), or the working/staged filter when "Apply together" mode is active. Pass
|
|
39
|
+
* the chosen one as `filterToDisplay`; if omitted, `filter` itself is used.
|
|
40
|
+
*
|
|
41
|
+
* @internal
|
|
42
|
+
*/
|
|
43
|
+
export function useDashboardMeasureValueFilterData(filter, filterToDisplay) {
|
|
44
|
+
const measures = useDashboardSelector(selectCatalogMeasures);
|
|
45
|
+
const separators = useDashboardSelector(selectSeparators);
|
|
46
|
+
const locale = useDashboardSelector(selectLocale);
|
|
47
|
+
const intl = useIntl();
|
|
48
|
+
const { measure, localIdentifier, title: customTitle } = filter.dashboardMeasureValueFilter;
|
|
49
|
+
const effective = filterToDisplay ?? filter;
|
|
50
|
+
const conditions = effective.dashboardMeasureValueFilter.conditions;
|
|
51
|
+
const catalogMetric = useMemo(() => findCatalogMetric(measure, measures), [measure, measures]);
|
|
52
|
+
const defaultMetricTitle = catalogMetric?.measure.title ?? objRefToString(measure);
|
|
53
|
+
const metricTitle = customTitle ?? defaultMetricTitle;
|
|
54
|
+
const format = catalogMetric?.measure.format;
|
|
55
|
+
const usePercentage = isPercentageFormat(format);
|
|
56
|
+
const conditionLabel = useMemo(() => getMeasureValueFilterConditionLabel(intl, conditions, { usePercentage, separators }), [intl, conditions, usePercentage, separators]);
|
|
57
|
+
const dropdownFilter = useMemo(() => ({
|
|
58
|
+
measureValueFilter: {
|
|
59
|
+
measure,
|
|
60
|
+
localIdentifier,
|
|
61
|
+
...(conditions && conditions.length > 0 ? { conditions } : {}),
|
|
62
|
+
},
|
|
63
|
+
}), [measure, localIdentifier, conditions]);
|
|
64
|
+
return {
|
|
65
|
+
measure,
|
|
66
|
+
localIdentifier,
|
|
67
|
+
customTitle,
|
|
68
|
+
catalogMetric,
|
|
69
|
+
defaultMetricTitle,
|
|
70
|
+
metricTitle,
|
|
71
|
+
format,
|
|
72
|
+
usePercentage,
|
|
73
|
+
conditions,
|
|
74
|
+
conditionLabel,
|
|
75
|
+
dropdownFilter,
|
|
76
|
+
separators,
|
|
77
|
+
locale,
|
|
78
|
+
intl,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Build the shared `<MeasureValueFilter />` prop bundle from the data hook output.
|
|
83
|
+
* Spread this into the SDK component and add host-specific props after.
|
|
84
|
+
*
|
|
85
|
+
* @internal
|
|
86
|
+
*/
|
|
87
|
+
export function getSharedDashboardMvfProps(data) {
|
|
88
|
+
return {
|
|
89
|
+
filter: data.dropdownFilter,
|
|
90
|
+
measureIdentifier: data.localIdentifier,
|
|
91
|
+
buttonTitle: data.metricTitle,
|
|
92
|
+
measureTitle: data.metricTitle,
|
|
93
|
+
usePercentage: data.usePercentage,
|
|
94
|
+
format: data.format,
|
|
95
|
+
useShortFormat: true,
|
|
96
|
+
displayTreatNullAsZeroOption: true,
|
|
97
|
+
separators: data.separators,
|
|
98
|
+
locale: data.locale,
|
|
99
|
+
enableOperatorSelection: true,
|
|
100
|
+
enableMultipleConditions: true,
|
|
101
|
+
isDimensionalityEnabled: false,
|
|
102
|
+
isFilterSummaryEnabled: true,
|
|
103
|
+
isHeaderEnabled: true,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
@@ -4966,6 +4966,11 @@ export declare type FluidLayoutCustomizationFn = (layout: IDashboardLayout<Exten
|
|
|
4966
4966
|
*/
|
|
4967
4967
|
export declare function formatKeyDriverAnalysisDateRange(range: DeepReadonly<[IKdaDataPoint, IKdaDataPoint]> | undefined, splitter: string): string;
|
|
4968
4968
|
|
|
4969
|
+
/**
|
|
4970
|
+
* @internal
|
|
4971
|
+
*/
|
|
4972
|
+
export declare function getAttributeFilters(filters: FilterContextItem[]): DashboardAttributeFilterItem[];
|
|
4973
|
+
|
|
4969
4974
|
/**
|
|
4970
4975
|
* @internal
|
|
4971
4976
|
* Gets author from capabilities and user
|
|
@@ -13945,9 +13950,20 @@ export declare interface IKdaDefinition {
|
|
|
13945
13950
|
*/
|
|
13946
13951
|
metrics?: IMeasure[];
|
|
13947
13952
|
/**
|
|
13948
|
-
*
|
|
13953
|
+
* Attribute filters to apply.
|
|
13954
|
+
*
|
|
13955
|
+
* Attribute filters drive both the KDA "segment-by attribute" UI in the dialog and the
|
|
13956
|
+
* scope of the change analysis computation.
|
|
13949
13957
|
*/
|
|
13950
13958
|
filters?: DashboardAttributeFilterItem[];
|
|
13959
|
+
/**
|
|
13960
|
+
* Measure value filters to apply to the change analysis computation.
|
|
13961
|
+
*
|
|
13962
|
+
* They are not editable in the dialog UI (KDA segments by attribute, not by metric value),
|
|
13963
|
+
* but the dashboard MVFs are propagated to the backend so the computation respects the
|
|
13964
|
+
* same metric-driven scope as the rest of the dashboard.
|
|
13965
|
+
*/
|
|
13966
|
+
measureValueFilters?: IDashboardMeasureValueFilter[];
|
|
13951
13967
|
/**
|
|
13952
13968
|
* Date attribute
|
|
13953
13969
|
*/
|
|
@@ -21309,11 +21325,6 @@ export declare function removeAttributeFilters(filterLocalIds: string[], correla
|
|
|
21309
21325
|
*/
|
|
21310
21326
|
export declare function removeDateFilter(dataSet: ObjRef, correlationId?: string): IRemoveDateFilters;
|
|
21311
21327
|
|
|
21312
|
-
/**
|
|
21313
|
-
* @internal
|
|
21314
|
-
*/
|
|
21315
|
-
export declare function removeDateFilters(filters: FilterContextItem[]): DashboardAttributeFilterItem[];
|
|
21316
|
-
|
|
21317
21328
|
/**
|
|
21318
21329
|
* Creates the RemoveDrillDownForInsightWidget command. Dispatching the created command will remove insight widget's
|
|
21319
21330
|
* drill definition for the provided measure.
|