@gooddata/sdk-ui-dashboard 11.35.0-alpha.5 → 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.
Files changed (65) hide show
  1. package/NOTICE +8 -8
  2. package/esm/__version.d.ts +1 -1
  3. package/esm/__version.js +1 -1
  4. package/esm/_staging/dashboard/dashboardFilterContext.js +18 -1
  5. package/esm/_staging/sharedHooks/useFiltersNamings.d.ts +1 -1
  6. package/esm/_staging/sharedHooks/useFiltersNamings.js +32 -5
  7. package/esm/index.d.ts +4 -5
  8. package/esm/index.js +2 -3
  9. package/esm/kdaDialog/dialog/hooks/useChangeAnalysis.js +21 -5
  10. package/esm/kdaDialog/internalTypes.d.ts +6 -1
  11. package/esm/kdaDialog/providers/Kda.js +4 -1
  12. package/esm/kdaDialog/providers/KdaState.js +1 -0
  13. package/esm/kdaDialog/types.d.ts +13 -2
  14. package/esm/model/commandHandlers/dashboard/common/parameterHydration.d.ts +11 -2
  15. package/esm/model/commandHandlers/dashboard/common/parameterHydration.js +21 -0
  16. package/esm/model/commandHandlers/dashboard/common/stateInitializers.js +44 -79
  17. package/esm/model/commandHandlers/dashboard/saveAsDashboardHandler.js +10 -5
  18. package/esm/model/commandHandlers/dashboard/saveDashboardHandler.js +11 -7
  19. package/esm/model/commandHandlers/drill/keyDriverAnalysisHandler.js +8 -3
  20. package/esm/model/store/_infra/generators.d.ts +1 -0
  21. package/esm/model/store/_infra/generators.js +4 -1
  22. package/esm/model/store/dashboardStore.d.ts +0 -2
  23. package/esm/model/store/dashboardStore.js +0 -2
  24. package/esm/model/store/filtering/dashboardFilterSelectors.d.ts +1 -1
  25. package/esm/model/store/filtering/dashboardFilterSelectors.js +8 -5
  26. package/esm/model/store/meta/metaSelectors.js +4 -3
  27. package/esm/model/store/tabs/filterContext/filterContextReducers.js +2 -2
  28. package/esm/model/store/tabs/index.d.ts +12 -0
  29. package/esm/model/store/tabs/index.js +2 -0
  30. package/esm/model/store/{parameters → tabs/parameters}/parametersReducers.d.ts +3 -7
  31. package/esm/model/store/tabs/parameters/parametersReducers.js +46 -0
  32. package/esm/model/store/tabs/parameters/parametersSelectors.d.ts +72 -0
  33. package/esm/model/store/tabs/parameters/parametersSelectors.js +228 -0
  34. package/esm/model/store/{parameters → tabs/parameters}/parametersState.d.ts +11 -1
  35. package/esm/model/store/tabs/parameters/parametersState.js +20 -0
  36. package/esm/model/store/tabs/tabsState.d.ts +2 -0
  37. package/esm/model/store/types.d.ts +0 -6
  38. package/esm/model/utils/widgetFilters.d.ts +1 -1
  39. package/esm/model/utils/widgetFilters.js +1 -1
  40. package/esm/presentation/automationFilters/components/AutomationFiltersSelect.js +8 -2
  41. package/esm/presentation/automationFilters/components/AutomationMeasureValueFilter.d.ts +10 -0
  42. package/esm/presentation/automationFilters/components/AutomationMeasureValueFilter.js +66 -0
  43. package/esm/presentation/automationFilters/components/AutomationMeasureValueFilterContext.d.ts +25 -0
  44. package/esm/presentation/automationFilters/components/AutomationMeasureValueFilterContext.js +28 -0
  45. package/esm/presentation/automationFilters/useAutomationFilters.d.ts +4 -1
  46. package/esm/presentation/automationFilters/useAutomationFilters.js +35 -4
  47. package/esm/presentation/automationFilters/utils.d.ts +2 -1
  48. package/esm/presentation/automationFilters/utils.js +34 -5
  49. package/esm/presentation/dragAndDrop/draggableParameterFilter/DefaultParameterDraggingComponent.js +1 -1
  50. package/esm/presentation/dragAndDrop/useFilterDeleteDrop.js +2 -2
  51. package/esm/presentation/filterBar/filterBar/DefaultFilterBar.js +1 -1
  52. package/esm/presentation/filterBar/measureValueFilter/DefaultDashboardMeasureValueFilter.js +8 -42
  53. package/esm/presentation/filterBar/measureValueFilter/useDashboardMeasureValueFilterData.d.ts +86 -0
  54. package/esm/presentation/filterBar/measureValueFilter/useDashboardMeasureValueFilterData.js +105 -0
  55. package/esm/presentation/filterBar/parameterFilter/DashboardParameterFilter.js +3 -3
  56. package/esm/presentation/filterBar/parameterFilter/DashboardParameterPicker.js +3 -3
  57. package/esm/presentation/widget/insight/ViewModeDashboardInsight/Insight/DashboardInsight.js +1 -1
  58. package/esm/sdk-ui-dashboard.d.ts +44 -32
  59. package/package.json +21 -21
  60. package/esm/model/store/parameters/index.d.ts +0 -12
  61. package/esm/model/store/parameters/index.js +0 -14
  62. package/esm/model/store/parameters/parametersReducers.js +0 -36
  63. package/esm/model/store/parameters/parametersSelectors.d.ts +0 -67
  64. package/esm/model/store/parameters/parametersSelectors.js +0 -122
  65. package/esm/model/store/parameters/parametersState.js +0 -4
@@ -14,7 +14,6 @@ import { selectCrossFilteringFiltersLocalIdentifiers } from "../../store/drill/d
14
14
  import { listedDashboardsActions } from "../../store/listedDashboards/index.js";
15
15
  import { metaActions } from "../../store/meta/index.js";
16
16
  import { selectDashboardDescriptor, selectPersistedDashboard, selectPersistedDashboardFilterContextAsFilterContextDefinition, } from "../../store/meta/metaSelectors.js";
17
- import { selectSmartPersistedDashboardParameters } from "../../store/parameters/parametersSelectors.js";
18
17
  import { selectIsInViewMode } from "../../store/renderMode/renderModeSelectors.js";
19
18
  import { savingActions } from "../../store/saving/index.js";
20
19
  import { selectAttributeFilterConfigsOverrides } from "../../store/tabs/attributeFilterConfigs/attributeFilterConfigsSelectors.js";
@@ -24,6 +23,7 @@ import { selectFilterContextAttributeFilters, selectFilterContextDefinition, } f
24
23
  import { tabsActions } from "../../store/tabs/index.js";
25
24
  import { filterOutCustomWidgets, selectBasicLayout } from "../../store/tabs/layout/layoutSelectors.js";
26
25
  import { selectMeasureValueFilterConfigsOverrides } from "../../store/tabs/measureValueFilterConfigs/measureValueFilterConfigsSelectors.js";
26
+ import { selectSmartPersistedTabsParameters } from "../../store/tabs/parameters/parametersSelectors.js";
27
27
  import { selectTabs } from "../../store/tabs/tabsSelectors.js";
28
28
  import { selectCurrentUser } from "../../store/user/userSelectors.js";
29
29
  import { changeRenderModeHandler } from "../renderMode/changeRenderModeHandler.js";
@@ -39,7 +39,7 @@ function createDashboard(ctx, saveAsCtx) {
39
39
  * @param tabs - Array of TabState objects from the dashboard state
40
40
  * @returns Array of IDashboardTab objects ready for saving to backend
41
41
  */
42
- function processExistingTabsForSaveAs(tabs, useOriginalFilterContext) {
42
+ function processExistingTabsForSaveAs(tabs, parametersByTab, useOriginalFilterContext) {
43
43
  return tabs.map((tab) => {
44
44
  const dateFilterConfig = tab.dateFilterConfig?.dateFilterConfig;
45
45
  const dateFilterConfigs = tab.dateFilterConfigs?.dateFilterConfigs;
@@ -61,6 +61,7 @@ function processExistingTabsForSaveAs(tabs, useOriginalFilterContext) {
61
61
  : tab.filterContext.filterContextDefinition),
62
62
  }
63
63
  : undefined;
64
+ const tabParameters = parametersByTab[tab.localIdentifier] ?? [];
64
65
  const result = {
65
66
  // explicitly type the result to avoid type errors caused by spread operators
66
67
  localIdentifier: tab.localIdentifier,
@@ -72,6 +73,9 @@ function processExistingTabsForSaveAs(tabs, useOriginalFilterContext) {
72
73
  ...dateFilterConfigsProp,
73
74
  ...attributeFilterConfigsProp,
74
75
  ...measureValueFilterConfigsProp,
76
+ // Always persist `parameters` (incl. `[]`) so V1 root fallback never re-hydrates stale
77
+ // root parameters when every tab has been emptied.
78
+ parameters: tabParameters,
75
79
  };
76
80
  return result;
77
81
  });
@@ -108,11 +112,13 @@ function* createDashboardSaveAsContext(cmd) {
108
112
  const dateFilterConfigs = yield select(selectDateFilterConfigsOverrides);
109
113
  const measureValueFilterConfigs = yield select(selectMeasureValueFilterConfigsOverrides);
110
114
  const tabs = yield select(selectTabs);
111
- const parameters = yield select(selectSmartPersistedDashboardParameters);
115
+ const parametersByTab = yield select(selectSmartPersistedTabsParameters);
112
116
  const capabilities = yield select(selectBackendCapabilities);
113
117
  const { isUnderStrictControl: _unusedProp, ...dashboardDescriptorRest } = dashboardDescriptor;
114
118
  // Process tabs if tabs exist
115
- const processedTabs = tabs && tabs.length > 0 ? processExistingTabsForSaveAs(tabs, useOriginalFilterContext) : undefined;
119
+ const processedTabs = tabs && tabs.length > 0
120
+ ? processExistingTabsForSaveAs(tabs, parametersByTab, useOriginalFilterContext)
121
+ : undefined;
116
122
  const dashboardFromState = {
117
123
  type: "IDashboard",
118
124
  ...dashboardDescriptorRest,
@@ -125,7 +131,6 @@ function* createDashboardSaveAsContext(cmd) {
125
131
  ...(dateFilterConfigs?.length ? { dateFilterConfigs } : {}),
126
132
  ...(measureValueFilterConfigs?.length ? { measureValueFilterConfigs } : {}),
127
133
  ...(processedTabs ? { tabs: processedTabs } : {}),
128
- ...(parameters.length ? { parameters } : {}),
129
134
  };
130
135
  const pluginsProp = persistedDashboard?.plugins ? { plugins: persistedDashboard.plugins } : {};
131
136
  const shareProp = capabilities.supportsAccessControl
@@ -18,7 +18,6 @@ import { selectLocale } from "../../store/config/configSelectors.js";
18
18
  import { listedDashboardsActions } from "../../store/listedDashboards/index.js";
19
19
  import { metaActions } from "../../store/meta/index.js";
20
20
  import { selectDashboardDescriptor, selectPersistedDashboard } from "../../store/meta/metaSelectors.js";
21
- import { selectSmartPersistedDashboardParameters } from "../../store/parameters/parametersSelectors.js";
22
21
  import { selectIsInViewMode } from "../../store/renderMode/renderModeSelectors.js";
23
22
  import { savingActions } from "../../store/saving/index.js";
24
23
  import { selectAttributeFilterConfigsOverrides } from "../../store/tabs/attributeFilterConfigs/attributeFilterConfigsSelectors.js";
@@ -28,6 +27,7 @@ import { selectFilterContextDefinition, selectFilterContextIdentity, } from "../
28
27
  import { tabsActions } from "../../store/tabs/index.js";
29
28
  import { filterOutCustomWidgets, selectBasicLayout } from "../../store/tabs/layout/layoutSelectors.js";
30
29
  import { selectMeasureValueFilterConfigsOverrides } from "../../store/tabs/measureValueFilterConfigs/measureValueFilterConfigsSelectors.js";
30
+ import { selectSmartPersistedTabsParameters } from "../../store/tabs/parameters/parametersSelectors.js";
31
31
  import { selectTabs } from "../../store/tabs/tabsSelectors.js";
32
32
  import { isTemporaryIdentity } from "../../utils/dashboardItemUtils.js";
33
33
  import { changeRenderModeHandler } from "../renderMode/changeRenderModeHandler.js";
@@ -66,9 +66,10 @@ export function getDashboardWithSharing(dashboard, sharingSupported = true, isNe
66
66
  * Converts TabState[] from the dashboard state into IDashboardTab[] for saving.
67
67
  *
68
68
  * @param tabs - Array of TabState objects from the dashboard state
69
+ * @param parametersByTab - Smart-persisted parameters keyed by tab localIdentifier
69
70
  * @returns Array of IDashboardTab objects ready for saving to backend
70
71
  */
71
- function processExistingTabs(tabs) {
72
+ function processExistingTabs(tabs, parametersByTab) {
72
73
  return tabs.map((tab) => {
73
74
  const dateFilterConfig = tab.dateFilterConfig?.dateFilterConfig;
74
75
  const dateFilterConfigProp = dateFilterConfig ? { dateFilterConfig } : {};
@@ -93,6 +94,7 @@ function processExistingTabs(tabs) {
93
94
  ...tab.filterContext.filterContextDefinition,
94
95
  }
95
96
  : undefined;
97
+ const tabParameters = parametersByTab[tab.localIdentifier] ?? [];
96
98
  const result = {
97
99
  // explicitly type the result to avoid type errors caused by spread operators
98
100
  localIdentifier: tab.localIdentifier,
@@ -105,6 +107,9 @@ function processExistingTabs(tabs) {
105
107
  ...attributeFilterConfigsProp,
106
108
  ...measureValueFilterConfigsProp,
107
109
  ...filterGroupsConfigProp,
110
+ // Always persist `parameters` (incl. `[]`) so V1 root fallback never re-hydrates stale
111
+ // root parameters when every tab has been emptied.
112
+ parameters: tabParameters,
108
113
  };
109
114
  return result;
110
115
  });
@@ -131,14 +136,14 @@ function createDefaultTab(layout, rootFilterContext, dateFilterConfig, attribute
131
136
  },
132
137
  ];
133
138
  }
134
- function resolveProcessedTabs(tabs, rootFilterContext, layout, dateFilterConfig, attributeFilterConfigs, dateFilterConfigs, measureValueFilterConfigs) {
139
+ function resolveProcessedTabs(tabs, rootFilterContext, layout, dateFilterConfig, attributeFilterConfigs, dateFilterConfigs, measureValueFilterConfigs, parametersByTab) {
135
140
  // If no tabs exist, create a default tab with root-level properties
136
141
  const shouldCreateDefaultTab = !tabs || tabs.length === 0;
137
142
  if (shouldCreateDefaultTab && rootFilterContext) {
138
143
  return createDefaultTab(layout, rootFilterContext, dateFilterConfig, attributeFilterConfigs, dateFilterConfigs, measureValueFilterConfigs);
139
144
  }
140
145
  if (tabs) {
141
- return processExistingTabs(tabs);
146
+ return processExistingTabs(tabs, parametersByTab);
142
147
  }
143
148
  return undefined;
144
149
  }
@@ -159,7 +164,7 @@ function* createDashboardSaveContext(cmd, isNewDashboard) {
159
164
  const dateFilterConfigs = yield select(selectDateFilterConfigsOverrides);
160
165
  const measureValueFilterConfigs = yield select(selectMeasureValueFilterConfigsOverrides);
161
166
  const tabs = yield select(selectTabs);
162
- const parameters = yield select(selectSmartPersistedDashboardParameters);
167
+ const parametersByTab = yield select(selectSmartPersistedTabsParameters);
163
168
  const capabilities = yield select(selectBackendCapabilities);
164
169
  /*
165
170
  * When updating an existing dashboard, the services expect that the dashboard definition to use for
@@ -179,7 +184,7 @@ function* createDashboardSaveContext(cmd, isNewDashboard) {
179
184
  ...filterContextDefinition,
180
185
  }
181
186
  : undefined;
182
- const processedTabs = resolveProcessedTabs(tabs, rootFilterContext, layout, dateFilterConfig, attributeFilterConfigs, dateFilterConfigs, measureValueFilterConfigs);
187
+ const processedTabs = resolveProcessedTabs(tabs, rootFilterContext, layout, dateFilterConfig, attributeFilterConfigs, dateFilterConfigs, measureValueFilterConfigs, parametersByTab);
183
188
  const locale = yield select(selectLocale);
184
189
  const translations = yield call(resolveMessages, locale);
185
190
  const title = (cmd.payload.title ?? dashboardDescriptor.title) || translations[messages.untitled.id];
@@ -198,7 +203,6 @@ function* createDashboardSaveContext(cmd, isNewDashboard) {
198
203
  dateFilterConfig,
199
204
  ...buildOptionalFilterConfigsProps(attributeFilterConfigs, dateFilterConfigs, measureValueFilterConfigs),
200
205
  ...(processedTabs ? { tabs: processedTabs } : {}),
201
- ...(parameters.length > 0 ? { parameters } : {}),
202
206
  ...pluginsProp,
203
207
  };
204
208
  const dashboardToSave = {
@@ -1,12 +1,12 @@
1
1
  // (C) 2021-2026 GoodData Corporation
2
2
  import { put, select } from "redux-saga/effects";
3
- import { areObjRefsEqual, dashboardAttributeFilterItemDisplayForm, isAttributeDescriptor, isMeasureDescriptor, } from "@gooddata/sdk-model";
3
+ import { areObjRefsEqual, dashboardAttributeFilterItemDisplayForm, isAttributeDescriptor, isDashboardMeasureValueFilter, isMeasureDescriptor, } from "@gooddata/sdk-model";
4
4
  import { keyDriverAnalysisRequested, keyDriverAnalysisResolved, } from "../../events/drill.js";
5
5
  import { invalidArgumentsProvided } from "../../events/general.js";
6
6
  import { generateFilterLocalIdentifier } from "../../store/_infra/generators.js";
7
7
  import { selectCatalogDateAttributes } from "../../store/catalog/catalogSelectors.js";
8
8
  import { selectWidgetByRef } from "../../store/tabs/layout/layoutSelectors.js";
9
- import { removeDateFilters, removeIgnoredWidgetFilters } from "../../utils/widgetFilters.js";
9
+ import { getAttributeFilters, removeIgnoredWidgetFilters } from "../../utils/widgetFilters.js";
10
10
  import { convertIntersectionToAttributeFilters } from "./common/intersectionUtils.js";
11
11
  export function* keyDriverAnalysisHandler(ctx, cmd) {
12
12
  const { drillDefinition, drillEvent, keyDriveItem, filters: availableFilters } = cmd.payload;
@@ -52,7 +52,11 @@ export function* keyDriverAnalysisHandler(ctx, cmd) {
52
52
  return dashboardFilter;
53
53
  });
54
54
  const widget = yield select(selectWidgetByRef(drillEvent.widgetRef));
55
- const attributeFilters = removeDateFilters(removeIgnoredWidgetFilters(availableFilters, widget));
55
+ const widgetFilters = removeIgnoredWidgetFilters(availableFilters, widget);
56
+ // KDA defines its own date range — drop date filters. Keep attribute and measure value
57
+ // filters so the change analysis respects the rest of the dashboard filter context.
58
+ const attributeFilters = getAttributeFilters(widgetFilters);
59
+ const measureValueFilters = widgetFilters.filter(isDashboardMeasureValueFilter);
56
60
  const filters = mergeFilters(intersectionFilters, attributeFilters);
57
61
  return keyDriverAnalysisResolved(ctx, cmd.payload.drillDefinition, cmd.payload.drillEvent, {
58
62
  metric: {
@@ -65,6 +69,7 @@ export function* keyDriverAnalysisHandler(ctx, cmd) {
65
69
  },
66
70
  metrics,
67
71
  filters,
72
+ measureValueFilters,
68
73
  dateAttribute: dateAttribute.attribute.ref,
69
74
  range: [
70
75
  {
@@ -1,2 +1,3 @@
1
1
  import { type ObjRef } from "@gooddata/sdk-model";
2
2
  export declare const generateFilterLocalIdentifier: (ref: ObjRef, index: number) => string;
3
+ export declare const generateMeasureValueFilterLocalIdentifier: (ref: ObjRef, index: number) => string;
@@ -1,5 +1,8 @@
1
- // (C) 2024 GoodData Corporation
1
+ // (C) 2024-2026 GoodData Corporation
2
2
  import { objRefToString } from "@gooddata/sdk-model";
3
3
  export const generateFilterLocalIdentifier = (ref, index) => {
4
4
  return `${objRefToString(ref)}_${index}_attributeFilter`;
5
5
  };
6
+ export const generateMeasureValueFilterLocalIdentifier = (ref, index) => {
7
+ return `${objRefToString(ref)}_${index}_measureValueFilter`;
8
+ };
@@ -127,7 +127,6 @@ export declare function createDashboardRootReducer({ queryCache }?: {
127
127
  dashboardPermissions: import("./dashboardPermissions/dashboardPermissionsState.js").DashboardPermissionsState;
128
128
  showWidgetAsTable: import("./showWidgetAsTable/showWidgetAsTableState.js").IShowWidgetAsTableState;
129
129
  notificationChannels: import("./notificationChannels/notificationChannelsState.js").INotificationChannelsState;
130
- parameters: import("./parameters/parametersState.js").IParametersState;
131
130
  automations: import("./automations/automationsState.js").IAutomationsState;
132
131
  users: import("./users/usersState.js").IUsersState;
133
132
  filterViews: import("./filterViews/filterViewsState.js").IFilterViewsState;
@@ -157,7 +156,6 @@ export declare function createDashboardRootReducer({ queryCache }?: {
157
156
  dashboardPermissions: import("./dashboardPermissions/dashboardPermissionsState.js").DashboardPermissionsState | undefined;
158
157
  showWidgetAsTable: import("./showWidgetAsTable/showWidgetAsTableState.js").IShowWidgetAsTableState | undefined;
159
158
  notificationChannels: import("./notificationChannels/notificationChannelsState.js").INotificationChannelsState | undefined;
160
- parameters: import("./parameters/parametersState.js").IParametersState | undefined;
161
159
  automations: import("./automations/automationsState.js").IAutomationsState | undefined;
162
160
  users: import("./users/usersState.js").IUsersState | undefined;
163
161
  filterViews: import("./filterViews/filterViewsState.js").IFilterViewsState | undefined;
@@ -31,7 +31,6 @@ import { listedDashboardsSliceReducer } from "./listedDashboards/index.js";
31
31
  import { loadingSliceReducer } from "./loading/index.js";
32
32
  import { metaSliceReducer } from "./meta/index.js";
33
33
  import { notificationChannelsSliceReducer } from "./notificationChannels/index.js";
34
- import { parametersSliceReducer } from "./parameters/index.js";
35
34
  import { permissionsSliceReducer } from "./permissions/index.js";
36
35
  import { renderModeSliceReducer } from "./renderMode/index.js";
37
36
  import { savingSliceReducer } from "./saving/index.js";
@@ -162,7 +161,6 @@ export function createDashboardRootReducer({ queryCache = (state = {}) => state,
162
161
  dashboardPermissions: dashboardPermissionsSliceReducer,
163
162
  showWidgetAsTable: showWidgetAsTableSliceReducer,
164
163
  notificationChannels: notificationChannelsSliceReducer,
165
- parameters: parametersSliceReducer,
166
164
  automations: automationsSliceReducer,
167
165
  users: usersSliceReducer,
168
166
  filterViews: filterViewsSliceReducer,
@@ -24,7 +24,7 @@ export declare const selectAutomationDefaultSelectedFilters: DashboardSelector<F
24
24
  * @alpha
25
25
  */
26
26
  export declare const selectAutomationCommonDateFilterId: DashboardSelector<string | undefined>;
27
- export declare function removeEmptyDashboardAttributeFilters(filters?: FilterContextItem[]): FilterContextItem[];
27
+ export declare function removeEmptyDashboardFilters(filters?: FilterContextItem[]): FilterContextItem[];
28
28
  export declare const isFilterContextItemHidden: (filter: FilterContextItem, filterConfigurations: {
29
29
  commonDateFilterConfig?: IDashboardDateFilterConfig | undefined;
30
30
  dateFilterWithDimensionConfigs: IDashboardDateFilterConfigItem[];
@@ -1,7 +1,7 @@
1
1
  // (C) 2024-2026 GoodData Corporation
2
2
  import { createSelector } from "@reduxjs/toolkit";
3
3
  import { generateDateFilterLocalIdentifier } from "@gooddata/sdk-backend-base";
4
- import { areObjRefsEqual, dashboardAttributeFilterItemLocalIdentifier, isAllValuesDashboardAttributeFilter, isDashboardAttributeFilterItem, isDashboardCommonDateFilter, isDashboardDateFilter, isDashboardDateFilterWithDimension, newAllTimeDashboardDateFilter, } from "@gooddata/sdk-model";
4
+ import { areObjRefsEqual, dashboardAttributeFilterItemLocalIdentifier, isAllDashboardMeasureValueFilter, isAllValuesDashboardAttributeFilter, isDashboardAttributeFilterItem, isDashboardCommonDateFilter, isDashboardDateFilter, isDashboardDateFilterWithDimension, isDashboardMeasureValueFilter, newAllTimeDashboardDateFilter, } from "@gooddata/sdk-model";
5
5
  import { selectCrossFilteringItems, selectCrossFilteringItemsByTab } from "../drill/drillSelectors.js";
6
6
  import { selectAttributeFilterConfigsOverrides, selectAttributeFilterConfigsOverridesByTab, } from "../tabs/attributeFilterConfigs/attributeFilterConfigsSelectors.js";
7
7
  import { selectDateFilterConfigOverrides, selectDateFilterConfigOverridesByTab, } from "../tabs/dateFilterConfig/dateFilterConfigSelectors.js";
@@ -55,7 +55,7 @@ export const selectAutomationAvailableDashboardFilters = createSelector(selectDa
55
55
  * @alpha
56
56
  */
57
57
  export const selectAutomationDefaultSelectedFilters = createSelector(selectAutomationAvailableDashboardFilters, (availableDashboardFilters) => {
58
- return removeEmptyDashboardAttributeFilters(availableDashboardFilters);
58
+ return removeEmptyDashboardFilters(availableDashboardFilters);
59
59
  });
60
60
  /**
61
61
  * @alpha
@@ -79,11 +79,14 @@ const removeCrossFilteringFilters = (filters, crossFilteringItems) => {
79
79
  return true;
80
80
  });
81
81
  };
82
- export function removeEmptyDashboardAttributeFilters(filters = []) {
82
+ export function removeEmptyDashboardFilters(filters = []) {
83
83
  return filters.filter((filter) => {
84
84
  if (isDashboardAttributeFilterItem(filter)) {
85
85
  return !isAllValuesDashboardAttributeFilter(filter);
86
86
  }
87
+ if (isDashboardMeasureValueFilter(filter)) {
88
+ return !isAllDashboardMeasureValueFilter(filter);
89
+ }
87
90
  return true;
88
91
  });
89
92
  }
@@ -166,8 +169,8 @@ export const selectAutomationFiltersByTab = createSelector(selectTabs, selectFil
166
169
  const lockedFilters = filtersWithCommonDate.filter((filter) => isFilterContextItemLocked(filter, filterConfigurations));
167
170
  // Get hidden filters
168
171
  const hiddenFilters = filtersWithCommonDate.filter((filter) => isFilterContextItemHidden(filter, filterConfigurations));
169
- // Get default selected filters (empty "All values" attribute filters removed)
170
- const defaultSelectedFilters = removeEmptyDashboardAttributeFilters(availableFilters);
172
+ // Get default selected filters (noop "All" filters removed — attribute and MVF)
173
+ const defaultSelectedFilters = removeEmptyDashboardFilters(availableFilters);
171
174
  return {
172
175
  tabId,
173
176
  tabTitle,
@@ -4,13 +4,13 @@ import { isEqual } from "lodash-es";
4
4
  import { invariant } from "ts-invariant";
5
5
  import { isDashboardLayoutEmpty } from "@gooddata/sdk-backend-spi";
6
6
  import { idRef, isDashboardAttributeFilter, isDashboardCommonDateFilter, isDashboardDateFilterWithDimension, isDashboardMeasureValueFilter, isDashboardTextAttributeFilter, isTempFilterContext, uriRef, } from "@gooddata/sdk-model";
7
- import { selectIsParametersChanged, selectSmartPersistedDashboardParameters, } from "../parameters/parametersSelectors.js";
8
7
  import { selectAttributeFilterConfigsOverridesByTab } from "../tabs/attributeFilterConfigs/attributeFilterConfigsSelectors.js";
9
8
  import { selectDateFilterConfigOverrides, selectDateFilterConfigOverridesByTab, } from "../tabs/dateFilterConfig/dateFilterConfigSelectors.js";
10
9
  import { selectDateFilterConfigsOverridesByTab } from "../tabs/dateFilterConfigs/dateFilterConfigsSelectors.js";
11
10
  import { selectFilterContextDefinition, selectFilterContextDefinitionsByTab, selectFilterContextIdentity, } from "../tabs/filterContext/filterContextSelectors.js";
12
11
  import { filterOutCustomWidgets, selectBasicLayout, selectBasicLayoutByTab, } from "../tabs/layout/layoutSelectors.js";
13
12
  import { selectMeasureValueFilterConfigsOverridesByTab } from "../tabs/measureValueFilterConfigs/measureValueFilterConfigsSelectors.js";
13
+ import { selectIsParametersChanged, selectSmartPersistedTabsParameters, } from "../tabs/parameters/parametersSelectors.js";
14
14
  import { selectActiveTabLocalIdentifier, selectTabs } from "../tabs/tabsSelectors.js";
15
15
  import { DEFAULT_TAB_ID } from "../tabs/tabsState.js";
16
16
  const selectSelf = createSelector((state) => state, (state) => state.meta);
@@ -71,6 +71,7 @@ export const selectPersistedDashboardTabs = createSelector(selectSelf, (state) =
71
71
  dateFilterConfig: persistedDashboard.dateFilterConfig,
72
72
  dateFilterConfigs: persistedDashboard.dateFilterConfigs,
73
73
  layout: persistedDashboard.layout,
74
+ parameters: persistedDashboard.parameters,
74
75
  },
75
76
  ];
76
77
  });
@@ -731,7 +732,7 @@ export const selectIsDashboardDirty = createSelector(selectIsNewDashboard, selec
731
732
  /**
732
733
  * @internal
733
734
  */
734
- export const selectDashboardWorkingDefinition = createSelector(selectPersistedDashboard, selectDashboardDescriptor, selectFilterContextDefinition, selectFilterContextIdentity, selectBasicLayout, selectDateFilterConfigOverrides, selectTabs, selectSmartPersistedDashboardParameters, (persistedDashboard, dashboardDescriptor, filterContextDefinition, filterContextIdentity, layout, dateFilterConfig, tabs, parameters) => {
735
+ export const selectDashboardWorkingDefinition = createSelector(selectPersistedDashboard, selectDashboardDescriptor, selectFilterContextDefinition, selectFilterContextIdentity, selectBasicLayout, selectDateFilterConfigOverrides, selectTabs, selectSmartPersistedTabsParameters, (persistedDashboard, dashboardDescriptor, filterContextDefinition, filterContextIdentity, layout, dateFilterConfig, tabs, parametersByTab) => {
735
736
  const dashboardIdentity = {
736
737
  ref: persistedDashboard?.ref,
737
738
  uri: persistedDashboard?.uri,
@@ -748,7 +749,6 @@ export const selectDashboardWorkingDefinition = createSelector(selectPersistedDa
748
749
  },
749
750
  layout,
750
751
  dateFilterConfig,
751
- ...(parameters.length > 0 ? { parameters } : {}),
752
752
  ...(tabs
753
753
  ? {
754
754
  tabs: tabs.map((tab) => ({
@@ -768,6 +768,7 @@ export const selectDashboardWorkingDefinition = createSelector(selectPersistedDa
768
768
  attributeFilterConfigs: tab.attributeFilterConfigs?.attributeFilterConfigs,
769
769
  measureValueFilterConfigs: tab.measureValueFilterConfigs?.measureValueFilterConfigs,
770
770
  filterGroupsConfig: tab.filterGroupsConfig,
771
+ parameters: parametersByTab[tab.localIdentifier] ?? [],
771
772
  })),
772
773
  }
773
774
  : {}),
@@ -1,7 +1,7 @@
1
1
  // (C) 2021-2026 GoodData Corporation
2
2
  import { invariant } from "ts-invariant";
3
3
  import { areObjRefsEqual, attributeElementsIsEmpty, dashboardAttributeFilterItemFilterElementsBy, dashboardAttributeFilterItemFilterElementsByDate, dashboardAttributeFilterItemLocalIdentifier, dashboardAttributeFilterItemValidateElementsBy, dashboardFilterLocalIdentifier, isAttributeElementsByRef, isDashboardArbitraryAttributeFilter, isDashboardAttributeFilter, isDashboardAttributeFilterItem, isDashboardCommonDateFilter, isDashboardDateFilter, isDashboardMatchAttributeFilter, isDashboardMeasureValueFilter, newAllTimeDashboardDateFilter, } from "@gooddata/sdk-model";
4
- import { generateFilterLocalIdentifier } from "../../_infra/generators.js";
4
+ import { generateFilterLocalIdentifier, generateMeasureValueFilterLocalIdentifier, } from "../../_infra/generators.js";
5
5
  import { getActiveTab, getTabOrActive } from "../tabsState.js";
6
6
  import { filterContextInitialState } from "./filterContextState.js";
7
7
  import { applyFilterContext, initializeFilterContext } from "./filterContextUtils.js";
@@ -674,7 +674,7 @@ const addMeasureValueFilter = (state, action) => {
674
674
  const filter = {
675
675
  dashboardMeasureValueFilter: {
676
676
  measure,
677
- localIdentifier: localIdentifier ?? generateFilterLocalIdentifier(measure, Math.max(0, index)),
677
+ localIdentifier: localIdentifier ?? generateMeasureValueFilterLocalIdentifier(measure, Math.max(0, index)),
678
678
  title,
679
679
  },
680
680
  };
@@ -561,4 +561,16 @@ export declare const tabsActions: import("@reduxjs/toolkit").CaseReducerActions<
561
561
  payload: string;
562
562
  type: string;
563
563
  }) => void | import("./tabsState.js").ITabsState | import("immer").WritableDraft<import("./tabsState.js").ITabsState>;
564
+ readonly addParameter: (state: import("immer").WritableDraft<import("./tabsState.js").ITabsState>, action: {
565
+ payload: import("./parameters/parametersReducers.js").IAddParameterPayload;
566
+ type: string;
567
+ }) => void | import("./tabsState.js").ITabsState | import("immer").WritableDraft<import("./tabsState.js").ITabsState>;
568
+ readonly setParameterRuntimeValue: (state: import("immer").WritableDraft<import("./tabsState.js").ITabsState>, action: {
569
+ payload: import("./parameters/parametersReducers.js").ISetParameterRuntimeValuePayload;
570
+ type: string;
571
+ }) => void | import("./tabsState.js").ITabsState | import("immer").WritableDraft<import("./tabsState.js").ITabsState>;
572
+ readonly removeParameter: (state: import("immer").WritableDraft<import("./tabsState.js").ITabsState>, action: {
573
+ payload: import("./parameters/parametersReducers.js").IRemoveParameterPayload;
574
+ type: string;
575
+ }) => void | import("./tabsState.js").ITabsState | import("immer").WritableDraft<import("./tabsState.js").ITabsState>;
564
576
  }, "tabs">;
@@ -6,6 +6,7 @@ import { dateFilterConfigsReducers } from "./dateFilterConfigs/dateFilterConfigs
6
6
  import { filterContextReducers } from "./filterContext/filterContextReducers.js";
7
7
  import { layoutReducers } from "./layout/layoutReducers.js";
8
8
  import { measureValueFilterConfigsReducers } from "./measureValueFilterConfigs/measureValueFilterConfigsReducers.js";
9
+ import { parametersReducers } from "./parameters/parametersReducers.js";
9
10
  import { tabsReducers } from "./tabsReducers.js";
10
11
  import { tabsInitialState } from "./tabsState.js";
11
12
  const allReducers = {
@@ -16,6 +17,7 @@ const allReducers = {
16
17
  ...measureValueFilterConfigsReducers,
17
18
  ...filterContextReducers,
18
19
  ...layoutReducers,
20
+ ...parametersReducers,
19
21
  };
20
22
  const tabsSlice = createSlice({
21
23
  name: "tabs",
@@ -1,9 +1,9 @@
1
1
  import { type Action, type CaseReducer } from "@reduxjs/toolkit";
2
2
  import { type IDashboardParameter, type ObjRef } from "@gooddata/sdk-model";
3
- import { type IDashboardParameterEntry, type IParametersState } from "./parametersState.js";
4
- type ParametersReducer<A extends Action> = CaseReducer<IParametersState, A>;
3
+ import { type ITabsState } from "../tabsState.js";
4
+ type ParametersReducer<A extends Action> = CaseReducer<ITabsState, A>;
5
5
  /**
6
- * Add a parameter to the dashboard. Initial `runtimeOverride` is `parameter.value`
6
+ * Add a parameter to the active tab. Initial `runtimeOverride` is `parameter.value`
7
7
  * (when pinned) otherwise the workspace default supplied by the caller.
8
8
  *
9
9
  * @alpha
@@ -38,9 +38,5 @@ export declare const parametersReducers: {
38
38
  payload: IRemoveParameterPayload;
39
39
  type: string;
40
40
  }>;
41
- setParameterEntries: ParametersReducer<{
42
- payload: IDashboardParameterEntry[];
43
- type: string;
44
- }>;
45
41
  };
46
42
  export {};
@@ -0,0 +1,46 @@
1
+ // (C) 2026 GoodData Corporation
2
+ import { areObjRefsEqual } from "@gooddata/sdk-model";
3
+ import { getActiveTab } from "../tabsState.js";
4
+ import { parametersInitialState } from "./parametersState.js";
5
+ const addParameter = (state, action) => {
6
+ const activeTab = getActiveTab(state);
7
+ if (!activeTab) {
8
+ return;
9
+ }
10
+ const { parameter, workspaceDefault } = action.payload;
11
+ const tabParameters = activeTab.parameters ?? parametersInitialState;
12
+ if (tabParameters.parameters.some((entry) => areObjRefsEqual(entry.parameter.ref, parameter.ref))) {
13
+ return;
14
+ }
15
+ activeTab.parameters = {
16
+ parameters: [
17
+ ...tabParameters.parameters,
18
+ { parameter, runtimeOverride: parameter.value ?? workspaceDefault },
19
+ ],
20
+ };
21
+ };
22
+ const setParameterRuntimeValue = (state, action) => {
23
+ const activeTab = getActiveTab(state);
24
+ if (!activeTab?.parameters) {
25
+ return;
26
+ }
27
+ const { ref, value } = action.payload;
28
+ const entry = activeTab.parameters.parameters.find((item) => areObjRefsEqual(item.parameter.ref, ref));
29
+ if (entry) {
30
+ entry.runtimeOverride = value;
31
+ }
32
+ };
33
+ const removeParameter = (state, action) => {
34
+ const activeTab = getActiveTab(state);
35
+ if (!activeTab?.parameters) {
36
+ return;
37
+ }
38
+ activeTab.parameters = {
39
+ parameters: activeTab.parameters.parameters.filter((entry) => !areObjRefsEqual(entry.parameter.ref, action.payload.ref)),
40
+ };
41
+ };
42
+ export const parametersReducers = {
43
+ addParameter,
44
+ setParameterRuntimeValue,
45
+ removeParameter,
46
+ };
@@ -0,0 +1,72 @@
1
+ import { type IDashboardParameter, type IInsightParameterValue, type ObjRef } from "@gooddata/sdk-model";
2
+ import { type DashboardSelector } from "../../types.js";
3
+ import { type IDashboardParameterEntry } from "./parametersState.js";
4
+ /**
5
+ * Returns the persisted-shape parameter entries currently held by the active tab.
6
+ *
7
+ * @alpha
8
+ */
9
+ export declare const selectDashboardParameters: DashboardSelector<IDashboardParameter[]>;
10
+ /**
11
+ * Returns currently active parameter references on the active tab.
12
+ *
13
+ * @alpha
14
+ */
15
+ export declare const selectActiveParameterRefKeys: DashboardSelector<ReadonlySet<string>>;
16
+ /**
17
+ * Returns the full per-parameter entries (persisted shape + ephemeral `runtimeOverride`) for the
18
+ * active tab.
19
+ *
20
+ * @internal
21
+ */
22
+ export declare const selectDashboardParameterEntries: DashboardSelector<IDashboardParameterEntry[]>;
23
+ /**
24
+ * Returns a selector that yields the entry held by the active tab for a given parameter ref,
25
+ * or `undefined` if no such entry exists.
26
+ *
27
+ * @alpha
28
+ */
29
+ export declare const selectDashboardParameterEntryByRef: (ref: ObjRef) => DashboardSelector<IDashboardParameterEntry | undefined>;
30
+ /**
31
+ * Returns a selector that yields the current `runtimeOverride` for a given parameter ref on the
32
+ * active tab, or `undefined` if the active tab does not hold an entry for that ref.
33
+ *
34
+ * @alpha
35
+ */
36
+ export declare const selectParameterRuntimeOverrideByRef: (ref: ObjRef) => DashboardSelector<number | undefined>;
37
+ /**
38
+ * Computes the dashboard parameters keyed by tab `localIdentifier` in the shape that would be
39
+ * persisted on save right now.
40
+ *
41
+ * @remarks
42
+ * Smart persistence applies independently per tab: `value` is dropped when equal to the
43
+ * workspace default, `label` is dropped when equal to the parameter title, all per tab.
44
+ * Non-resolved entries (catalog not loaded, gated off, ref missing) are emitted verbatim from
45
+ * the previously persisted entry on the same tab when available. V1 fallback applies when no
46
+ * tab in the persisted dashboard carries `parameters` — the persisted root array is used as the
47
+ * persistence source for every tab.
48
+ *
49
+ * @internal
50
+ */
51
+ export declare const selectSmartPersistedTabsParameters: DashboardSelector<Record<string, IDashboardParameter[]>>;
52
+ /**
53
+ * Returns true if the dashboard parameters that would be persisted differ from the persisted
54
+ * version on any tab.
55
+ *
56
+ * @alpha
57
+ */
58
+ export declare const selectIsParametersChanged: DashboardSelector<boolean>;
59
+ /**
60
+ * Returns the parameter values to inject into the widget's `IExecutionConfig.parameterValues`.
61
+ *
62
+ * @remarks
63
+ * The widget's owning tab is resolved from layout, then the result is the intersection of that
64
+ * tab's parameter entries and the parameters referenced by the widget's insight (per
65
+ * `insightParameters`). Dashboard parameters not referenced by the widget's insight are excluded
66
+ * so that adding/removing unrelated parameters does not invalidate the widget's `defFingerprint`.
67
+ * Returns an empty array when `enableParameters` is off so persisted parameter values cannot
68
+ * silently affect execution while the UI is hidden.
69
+ *
70
+ * @alpha
71
+ */
72
+ export declare const selectEffectiveParameterValuesForWidget: (ref: ObjRef | undefined) => DashboardSelector<IInsightParameterValue[]>;