@gooddata/sdk-ui-dashboard 11.65.0-alpha.7 → 11.65.0-alpha.9

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 (98) hide show
  1. package/NOTICE +3 -91
  2. package/esm/__version.d.ts +1 -1
  3. package/esm/__version.js +1 -1
  4. package/esm/index.d.ts +3 -2
  5. package/esm/index.d.ts.map +1 -1
  6. package/esm/model/commandHandlers/filterContext/attributeFilter/changeAttributeDisplayFormHandler.d.ts.map +1 -1
  7. package/esm/model/commandHandlers/filterContext/attributeFilter/changeAttributeDisplayFormHandler.js +8 -7
  8. package/esm/model/commandHandlers/filterContext/attributeFilter/changeAttributeFilterSelectionHandler.d.ts.map +1 -1
  9. package/esm/model/commandHandlers/filterContext/attributeFilter/changeAttributeFilterSelectionHandler.js +19 -28
  10. package/esm/model/commandHandlers/filterContext/attributeFilter/removeAttributeFiltersHandler.d.ts.map +1 -1
  11. package/esm/model/commandHandlers/filterContext/attributeFilter/removeAttributeFiltersHandler.js +4 -5
  12. package/esm/model/commandHandlers/filterContext/attributeFilter/replaceAttributeFilterItemSelectionHandler.d.ts.map +1 -1
  13. package/esm/model/commandHandlers/filterContext/attributeFilter/replaceAttributeFilterItemSelectionHandler.js +14 -15
  14. package/esm/model/commandHandlers/filterContext/attributeFilter/resolveDisplayFormMetadata.d.ts +4 -1
  15. package/esm/model/commandHandlers/filterContext/attributeFilter/resolveDisplayFormMetadata.d.ts.map +1 -1
  16. package/esm/model/commandHandlers/filterContext/attributeFilter/resolveDisplayFormMetadata.js +11 -2
  17. package/esm/model/commandHandlers/filterContext/changeFilterContextSelectionHandler.d.ts.map +1 -1
  18. package/esm/model/commandHandlers/filterContext/changeFilterContextSelectionHandler.js +23 -45
  19. package/esm/model/commandHandlers/filterContext/common.d.ts +6 -5
  20. package/esm/model/commandHandlers/filterContext/common.d.ts.map +1 -1
  21. package/esm/model/commandHandlers/filterContext/common.js +12 -18
  22. package/esm/model/commandHandlers/filterContext/dateFilter/changeDateFilterSelectionHandler.d.ts.map +1 -1
  23. package/esm/model/commandHandlers/filterContext/dateFilter/changeDateFilterSelectionHandler.js +30 -36
  24. package/esm/model/commandHandlers/filterContext/measureValueFilter/changeMeasureValueFilterConditionHandler.d.ts.map +1 -1
  25. package/esm/model/commandHandlers/filterContext/measureValueFilter/changeMeasureValueFilterConditionHandler.js +11 -17
  26. package/esm/model/commandHandlers/filterContext/measureValueFilter/changeMeasureValueFilterDimensionalityHandler.d.ts.map +1 -1
  27. package/esm/model/commandHandlers/filterContext/measureValueFilter/changeMeasureValueFilterDimensionalityHandler.js +7 -10
  28. package/esm/model/commandHandlers/filterContext/tabSync/expandActionsForTabSync.d.ts +15 -0
  29. package/esm/model/commandHandlers/filterContext/tabSync/expandActionsForTabSync.d.ts.map +1 -0
  30. package/esm/model/commandHandlers/filterContext/tabSync/expandActionsForTabSync.js +88 -0
  31. package/esm/model/commandHandlers/filterContext/tabSync/tabSyncRules.d.ts +11 -0
  32. package/esm/model/commandHandlers/filterContext/tabSync/tabSyncRules.d.ts.map +1 -0
  33. package/esm/model/commandHandlers/filterContext/tabSync/tabSyncRules.js +335 -0
  34. package/esm/model/commandHandlers/filterContext/tabSync/tabSyncSaga.d.ts +52 -0
  35. package/esm/model/commandHandlers/filterContext/tabSync/tabSyncSaga.d.ts.map +1 -0
  36. package/esm/model/commandHandlers/filterContext/tabSync/tabSyncSaga.js +60 -0
  37. package/esm/model/commandHandlers/filterContext/tabSync/tabSyncScope.d.ts +69 -0
  38. package/esm/model/commandHandlers/filterContext/tabSync/tabSyncScope.d.ts.map +1 -0
  39. package/esm/model/commandHandlers/filterContext/tabSync/tabSyncScope.js +2 -0
  40. package/esm/model/commandHandlers/parameters/changeParameterValuesHandler.d.ts +2 -1
  41. package/esm/model/commandHandlers/parameters/changeParameterValuesHandler.d.ts.map +1 -1
  42. package/esm/model/commandHandlers/parameters/changeParameterValuesHandler.js +41 -10
  43. package/esm/model/commands/parameters.d.ts +11 -1
  44. package/esm/model/commands/parameters.d.ts.map +1 -1
  45. package/esm/model/commands/parameters.js +2 -1
  46. package/esm/model/store/tabs/attributeFilterConfigs/attributeFilterConfigsReducers.d.ts +75 -5
  47. package/esm/model/store/tabs/attributeFilterConfigs/attributeFilterConfigsReducers.d.ts.map +1 -1
  48. package/esm/model/store/tabs/attributeFilterConfigs/attributeFilterConfigsReducers.js +35 -60
  49. package/esm/model/store/tabs/dateFilterConfigs/dateFilterConfigsReducers.js +1 -1
  50. package/esm/model/store/tabs/filterContext/filterContextReducers.d.ts +139 -31
  51. package/esm/model/store/tabs/filterContext/filterContextReducers.d.ts.map +1 -1
  52. package/esm/model/store/tabs/filterContext/filterContextReducers.js +314 -529
  53. package/esm/model/store/tabs/filterContext/filterSync.d.ts +35 -13
  54. package/esm/model/store/tabs/filterContext/filterSync.d.ts.map +1 -1
  55. package/esm/model/store/tabs/filterContext/filterSync.js +79 -58
  56. package/esm/model/store/tabs/index.d.ts +10 -12
  57. package/esm/model/store/tabs/index.d.ts.map +1 -1
  58. package/esm/model/store/tabs/layout/layoutReducers.d.ts +1 -0
  59. package/esm/model/store/tabs/layout/layoutReducers.d.ts.map +1 -1
  60. package/esm/model/store/tabs/measureValueFilterConfigs/measureValueFilterConfigsReducers.d.ts.map +1 -1
  61. package/esm/model/store/tabs/parameters/parametersReducers.d.ts +0 -5
  62. package/esm/model/store/tabs/parameters/parametersReducers.d.ts.map +1 -1
  63. package/esm/model/store/tabs/parameters/parametersReducers.js +8 -7
  64. package/esm/model/store/tabs/parameters/parametersSelectors.d.ts +7 -0
  65. package/esm/model/store/tabs/parameters/parametersSelectors.d.ts.map +1 -1
  66. package/esm/model/store/tabs/parameters/parametersSelectors.js +16 -0
  67. package/esm/model/store/tabs/tabsReducers.d.ts +8 -4
  68. package/esm/model/store/tabs/tabsReducers.d.ts.map +1 -1
  69. package/esm/model/store/tabs/tabsReducers.js +15 -18
  70. package/esm/model/store/tabs/tabsState.d.ts +0 -10
  71. package/esm/model/store/tabs/tabsState.d.ts.map +1 -1
  72. package/esm/model/store/tabs/tabsState.js +0 -20
  73. package/esm/model/utils/attributeFilterMatching.d.ts +10 -0
  74. package/esm/model/utils/attributeFilterMatching.d.ts.map +1 -1
  75. package/esm/model/utils/attributeFilterMatching.js +14 -3
  76. package/esm/model/utils/attributeFilterSelectionTypeCompatibility.d.ts +8 -0
  77. package/esm/model/utils/attributeFilterSelectionTypeCompatibility.d.ts.map +1 -1
  78. package/esm/model/utils/attributeFilterSelectionTypeCompatibility.js +14 -4
  79. package/esm/presentation/dashboard/components/DashboardInner.js +1 -1
  80. package/esm/presentation/dashboard/components/DashboardInteractionComposing.d.ts +2 -1
  81. package/esm/presentation/dashboard/components/DashboardInteractionComposing.d.ts.map +1 -1
  82. package/esm/presentation/dashboard/components/DashboardInteractionComposing.js +9 -4
  83. package/esm/presentation/dashboard/types.d.ts +5 -0
  84. package/esm/presentation/dashboard/types.d.ts.map +1 -1
  85. package/esm/presentation/filterBar/filterBar/hooks/useResetFiltersButton.d.ts.map +1 -1
  86. package/esm/presentation/filterBar/filterBar/hooks/useResetFiltersButton.js +4 -1
  87. package/esm/presentation/localization/bundles/en-US.localization-bundle.d.ts +4 -0
  88. package/esm/presentation/localization/bundles/en-US.localization-bundle.d.ts.map +1 -1
  89. package/esm/presentation/localization/bundles/en-US.localization-bundle.js +4 -0
  90. package/esm/presentation/widget/insightMenu/DefaultDashboardInsightMenu/DashboardInsightMenu/index.d.ts.map +1 -1
  91. package/esm/presentation/widget/insightMenu/DefaultDashboardInsightMenu/DashboardInsightMenu/index.js +10 -1
  92. package/esm/sdk-ui-dashboard.d.ts +262 -43
  93. package/package.json +21 -21
  94. package/styles/css/dashboard.css +10 -2
  95. package/styles/css/dashboard.css.map +1 -1
  96. package/styles/css/main.css +10 -2
  97. package/styles/css/main.css.map +1 -1
  98. package/styles/scss/dashboard.scss +11 -2
@@ -1,15 +1,15 @@
1
1
  // (C) 2026 GoodData Corporation
2
- import { call, put, select } from "redux-saga/effects";
2
+ import { call, select } from "redux-saga/effects";
3
3
  import { dashboardAttributeFilterItemDisplayForm } from "@gooddata/sdk-model";
4
4
  import { attributeFilterItemSelectionReplaced } from "../../../events/filters.js";
5
5
  import { invalidArgumentsProvided } from "../../../events/general.js";
6
6
  import { dispatchDashboardEvent } from "../../../store/_infra/eventDispatcher.js";
7
7
  import { selectIsApplyFiltersAllAtOnceEnabledAndSet } from "../../../store/config/configSelectors.js";
8
- import { selectCrossFilteringFiltersLocalIdentifiersByTab, selectIsCrossFiltering, selectIsFilterFromCrossFilteringByLocalIdentifier, } from "../../../store/drill/drillSelectors.js";
9
- import { selectEnablePersistentFiltersAcrossTabs } from "../../../store/meta/metaSelectors.js";
8
+ import { selectIsCrossFiltering, selectIsFilterFromCrossFilteringByLocalIdentifier, } from "../../../store/drill/drillSelectors.js";
10
9
  import { selectFilterContextAttributeFilterItemByLocalId } from "../../../store/tabs/filterContext/filterContextSelectors.js";
11
10
  import { tabsActions } from "../../../store/tabs/index.js";
12
- import { dispatchFilterContextChanged, resetCrossFiltering } from "../common.js";
11
+ import { resetCrossFiltering } from "../common.js";
12
+ import { beginTabSync, endTabSync, putTabSynced } from "../tabSync/tabSyncSaga.js";
13
13
  import { resolveAndRegisterDisplayFormMetadata } from "./resolveDisplayFormMetadata.js";
14
14
  export function* replaceAttributeFilterItemSelectionHandler(ctx, cmd) {
15
15
  const { filterLocalId, filter, isWorkingSelectionChange, isSelectionInvalid } = cmd.payload;
@@ -19,16 +19,15 @@ export function* replaceAttributeFilterItemSelectionHandler(ctx, cmd) {
19
19
  throw invalidArgumentsProvided(ctx, cmd, `Filter with filterLocalId ${filterLocalId} not found.`);
20
20
  }
21
21
  const isApplyAllAtOnceEnabledAndSet = yield select(selectIsApplyFiltersAllAtOnceEnabledAndSet);
22
- const crossFilteringLocalIdsByTab = yield select(selectCrossFilteringFiltersLocalIdentifiersByTab);
23
- const enablePersistentFiltersAcrossTabs = yield select(selectEnablePersistentFiltersAcrossTabs);
24
- yield put(tabsActions.replaceAttributeFilterItem({
25
- filterLocalId,
26
- filter,
27
- isWorkingSelectionChange: isWorkingSelectionChange && isApplyAllAtOnceEnabledAndSet,
28
- isSelectionInvalid,
29
- crossFilteringLocalIdsByTab,
30
- enablePersistentFiltersAcrossTabs,
31
- }));
22
+ const session = yield call(beginTabSync);
23
+ yield call(putTabSynced, session, [
24
+ tabsActions.replaceAttributeFilterItem({
25
+ filterLocalId,
26
+ filter,
27
+ isWorkingSelectionChange: isWorkingSelectionChange && isApplyAllAtOnceEnabledAndSet,
28
+ isSelectionInvalid,
29
+ }),
30
+ ]);
32
31
  // Ensure the new filter's displayForm is registered in the displayFormsMap.
33
32
  // This is needed for cross-type migration (e.g. text→list) where the new filter's
34
33
  // displayForm (primary label) may not have been registered previously.
@@ -46,5 +45,5 @@ export function* replaceAttributeFilterItemSelectionHandler(ctx, cmd) {
46
45
  (!isWorkingSelectionChange || !isApplyAllAtOnceEnabledAndSet)) {
47
46
  yield call(resetCrossFiltering, cmd);
48
47
  }
49
- yield call(dispatchFilterContextChanged, ctx, cmd);
48
+ yield call(endTabSync, ctx, cmd, session);
50
49
  }
@@ -1,10 +1,13 @@
1
1
  import { type SagaIterator } from "redux-saga";
2
2
  import { type IAttributeDisplayFormMetadataObject, type ObjRef } from "@gooddata/sdk-model";
3
+ import { type ITabSyncSession } from "../tabSync/tabSyncSaga.js";
3
4
  /**
4
5
  * Resolves display form metadata for the given ObjRef and registers it in the store
5
6
  * so that selectors like selectAttributeFilterDisplayFormsMap can resolve it.
6
7
  *
8
+ * With a tab sync `session`, the display form is registered on the synced tabs too.
9
+ *
7
10
  * @returns the resolved display form metadata, or undefined if not found
8
11
  */
9
- export declare function resolveAndRegisterDisplayFormMetadata(displayForm: ObjRef): SagaIterator<IAttributeDisplayFormMetadataObject | undefined>;
12
+ export declare function resolveAndRegisterDisplayFormMetadata(displayForm: ObjRef, session?: ITabSyncSession): SagaIterator<IAttributeDisplayFormMetadataObject | undefined>;
10
13
  //# sourceMappingURL=resolveDisplayFormMetadata.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"resolveDisplayFormMetadata.d.ts","sourceRoot":"","sources":["../../../../../src/model/commandHandlers/filterContext/attributeFilter/resolveDisplayFormMetadata.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAG/C,OAAO,EACH,KAAK,mCAAmC,EAExC,KAAK,MAAM,EACd,MAAM,qBAAqB,CAAC;AAQ7B;;;;;GAKG;AACH,wBAAiB,qCAAqC,CAClD,WAAW,EAAE,MAAM,GACpB,YAAY,CAAC,mCAAmC,GAAG,SAAS,CAAC,CAoB/D"}
1
+ {"version":3,"file":"resolveDisplayFormMetadata.d.ts","sourceRoot":"","sources":["../../../../../src/model/commandHandlers/filterContext/attributeFilter/resolveDisplayFormMetadata.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAG/C,OAAO,EACH,KAAK,mCAAmC,EAExC,KAAK,MAAM,EACd,MAAM,qBAAqB,CAAC;AAO7B,OAAO,EAAE,KAAK,eAAe,EAAgB,MAAM,2BAA2B,CAAC;AAE/E;;;;;;;GAOG;AACH,wBAAiB,qCAAqC,CAClD,WAAW,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE,eAAe,GAC1B,YAAY,CAAC,mCAAmC,GAAG,SAAS,CAAC,CAyB/D"}
@@ -5,13 +5,16 @@ import { queryAttributeByDisplayForm } from "../../../queries/attributes.js";
5
5
  import { query } from "../../../store/_infra/queryCall.js";
6
6
  import { selectAllCatalogDisplayFormsMap } from "../../../store/catalog/catalogSelectors.js";
7
7
  import { tabsActions } from "../../../store/tabs/index.js";
8
+ import { putTabSynced } from "../tabSync/tabSyncSaga.js";
8
9
  /**
9
10
  * Resolves display form metadata for the given ObjRef and registers it in the store
10
11
  * so that selectors like selectAttributeFilterDisplayFormsMap can resolve it.
11
12
  *
13
+ * With a tab sync `session`, the display form is registered on the synced tabs too.
14
+ *
12
15
  * @returns the resolved display form metadata, or undefined if not found
13
16
  */
14
- export function* resolveAndRegisterDisplayFormMetadata(displayForm) {
17
+ export function* resolveAndRegisterDisplayFormMetadata(displayForm, session) {
15
18
  const catalogDisplayFormsMap = yield select(selectAllCatalogDisplayFormsMap);
16
19
  let displayFormData = catalogDisplayFormsMap.get(displayForm);
17
20
  if (!displayFormData) {
@@ -20,7 +23,13 @@ export function* resolveAndRegisterDisplayFormMetadata(displayForm) {
20
23
  displayFormData = attributeDisplayFormsMap.get(displayForm);
21
24
  }
22
25
  if (displayFormData) {
23
- yield put(tabsActions.addAttributeFilterDisplayForm(displayFormData));
26
+ const action = tabsActions.addAttributeFilterDisplayForm(displayFormData);
27
+ if (session) {
28
+ yield call(putTabSynced, session, [action]);
29
+ }
30
+ else {
31
+ yield put(action);
32
+ }
24
33
  }
25
34
  return displayFormData;
26
35
  }
@@ -1 +1 @@
1
- {"version":3,"file":"changeFilterContextSelectionHandler.d.ts","sourceRoot":"","sources":["../../../../src/model/commandHandlers/filterContext/changeFilterContextSelectionHandler.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAyC/C,OAAO,EAAE,KAAK,4BAA4B,EAAE,MAAM,2BAA2B,CAAC;AAyC9E,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAyNnE,wBAAiB,mCAAmC,CAChD,GAAG,EAAE,gBAAgB,EACrB,GAAG,EAAE,4BAA4B,GAClC,YAAY,CAAC,IAAI,CAAC,CA4OpB"}
1
+ {"version":3,"file":"changeFilterContextSelectionHandler.d.ts","sourceRoot":"","sources":["../../../../src/model/commandHandlers/filterContext/changeFilterContextSelectionHandler.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAyC/C,OAAO,EAAE,KAAK,4BAA4B,EAAE,MAAM,2BAA2B,CAAC;AAuC9E,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAgOnE,wBAAiB,mCAAmC,CAChD,GAAG,EAAE,gBAAgB,EACrB,GAAG,EAAE,4BAA4B,GAClC,YAAY,CAAC,IAAI,CAAC,CAqOpB"}
@@ -1,16 +1,13 @@
1
1
  // (C) 2021-2026 GoodData Corporation
2
2
  import { compact, partition, uniqBy } from "lodash-es";
3
- import { batchActions } from "redux-batched-actions";
4
- import { all, call, put, select } from "redux-saga/effects";
3
+ import { all, call, select } from "redux-saga/effects";
5
4
  import { NotSupported } from "@gooddata/sdk-backend-spi";
6
5
  import { areObjRefsEqual, attributeElementsIsEmpty, dashboardAttributeFilterItemDisplayForm, dashboardAttributeFilterItemFilterElementsBy, dashboardAttributeFilterItemFilterElementsByDate, dashboardAttributeFilterItemLocalIdentifier, dashboardAttributeFilterItemValidateElementsBy, dashboardFilterLocalIdentifier, dashboardFilterObjRef, dashboardMeasureValueFilterLocalIdentifier, getAttributeElementsItems, isAllTimeDashboardDateFilter, isDashboardArbitraryAttributeFilter, isDashboardAttributeFilter, isDashboardAttributeFilterItem, isDashboardCommonDateFilter, isDashboardDateFilter, isDashboardMeasureValueFilter, isDashboardTextAttributeFilter, isSingleSelectionFilter, isUriRef, objRefToString, serializeObjRef, updateAttributeElementsItems, } from "@gooddata/sdk-model";
7
6
  import { dashboardFilterToFilterContextItem } from "../../../_staging/dashboard/dashboardFilterContext.js";
8
7
  import { invalidArgumentsProvided } from "../../events/general.js";
9
8
  import { dispatchDashboardEvent } from "../../store/_infra/eventDispatcher.js";
10
- import { selectCrossFilteringFiltersLocalIdentifiersByTab } from "../../store/drill/drillSelectors.js";
11
9
  import { selectRestrictedDashboardFilterLocalIdentifiers, selectRestrictedDashboardFilterLocalIdentifiersForTab, } from "../../store/filtering/dashboardFilterSelectors.js";
12
10
  import { isDashboardFilterUsingRestrictedObject } from "../../store/filtering/restrictedFilterUtils.js";
13
- import { selectEnablePersistentFiltersAcrossTabs } from "../../store/meta/metaSelectors.js";
14
11
  import { selectAttributeFilterConfigsOverrides, selectAttributeFilterConfigsOverridesByTab, selectAttributeFilterConfigsSelectionTypeMap, selectAttributeFilterConfigsSelectionTypeMapByTab, } from "../../store/tabs/attributeFilterConfigs/attributeFilterConfigsSelectors.js";
15
12
  import { isDisplayFormRefOf, selectAttributeFilterDisplayFormsMap, selectFilterContextAttributeFilterItems, selectFilterContextAttributeFilterItemsForTab, selectFilterContextDateFilterByDataSet, selectFilterContextDateFilterByDataSetForTab, selectFilterContextDateFiltersWithDimension, selectFilterContextDateFiltersWithDimensionForTab, selectFilterContextFilters, selectFilterContextMeasureValueFilters, selectFiltersForTab, } from "../../store/tabs/filterContext/filterContextSelectors.js";
16
13
  import { tabsActions } from "../../store/tabs/index.js";
@@ -21,7 +18,8 @@ import { resolveAttributeMetadata } from "../../utils/attributeResolver.js";
21
18
  import { resolveDisplayFormMetadata, } from "../../utils/displayFormResolver.js";
22
19
  import { resolveAndRegisterDisplayFormMetadata } from "./attributeFilter/resolveDisplayFormMetadata.js";
23
20
  import { computedAttributesDisabledMessage, findDisabledComputedAttributeRef, } from "./attributeFilter/validation/computedAttributesEnabledValidation.js";
24
- import { canApplyDateFilter, captureFilterContextByTabSnapshot, dispatchFilterContextChanged, dispatchFilterContextChangedForMutatedTabs, } from "./common.js";
21
+ import { canApplyDateFilter } from "./common.js";
22
+ import { beginTabSync, endTabSync, putTabSynced } from "./tabSync/tabSyncSaga.js";
25
23
  function classifyRestore(type, restoresOriginal) {
26
24
  // A computed key is not inferred as a single-property mapped type.
27
25
  return { [type]: restoresOriginal };
@@ -34,8 +32,8 @@ const RESTORE_TARGET_ORIGINAL = {
34
32
  ...classifyRestore(tabsActions.changeMeasureValueFilterCondition.type, true),
35
33
  ...classifyRestore(tabsActions.setMeasureValueFilterDimensionality.type, true),
36
34
  ...classifyRestore(tabsActions.addAttributeFilterDisplayForm.type, false),
37
- ...classifyRestore(tabsActions.changeAttributeDisplayForm.type, false),
38
- ...classifyRestore(tabsActions.changeDisplayAsLabel.type, false),
35
+ ...classifyRestore(tabsActions.changeAttributeDisplayForm.type, true),
36
+ ...classifyRestore(tabsActions.changeDisplayAsLabel.type, true),
39
37
  };
40
38
  /**
41
39
  * Reset persists one payload (the active tab's saved values). Mark the value-writing actions so
@@ -108,6 +106,13 @@ function* selectFilterContextDateFiltersWithDimensionTabAware(tabLocalIdentifier
108
106
  ? yield select(selectFilterContextDateFiltersWithDimensionForTab(tabLocalIdentifier))
109
107
  : yield select(selectFilterContextDateFiltersWithDimension);
110
108
  }
109
+ function* selectFilterContextMeasureValueFiltersTabAware(tabLocalIdentifier) {
110
+ if (tabLocalIdentifier) {
111
+ const filters = yield select(selectFiltersForTab(tabLocalIdentifier));
112
+ return filters.filter(isDashboardMeasureValueFilter);
113
+ }
114
+ return yield select(selectFilterContextMeasureValueFilters);
115
+ }
111
116
  function* selectAttributeFilterConfigsSelectionTypeMapTabAware(tabLocalIdentifier) {
112
117
  if (tabLocalIdentifier) {
113
118
  const byTab = yield select(selectAttributeFilterConfigsSelectionTypeMapByTab);
@@ -214,10 +219,9 @@ export function* changeFilterContextSelectionHandler(ctx, cmd) {
214
219
  call(getAttributeFiltersUpdateActions, [...attributeFilters].reverse(), textAttributeFilters, attributeFilterConfigs, resetOthers, ctx, tabLocalIdentifier, selectionTypeMap, matchByLocalIdentifier),
215
220
  call(getDateFilterUpdateActions, commonDateFilter, resetOthers, tabLocalIdentifier),
216
221
  call(getDateFiltersUpdateActions, dateFiltersWithDimension, resetOthers, tabLocalIdentifier),
217
- call(getMeasureValueFiltersUpdateActions, measureValueFilters, resetOthers),
222
+ call(getMeasureValueFiltersUpdateActions, measureValueFilters, resetOthers, tabLocalIdentifier),
218
223
  ]);
219
- const enablePersistentFiltersAcrossTabs = yield select(selectEnablePersistentFiltersAcrossTabs);
220
- const filterContextSnapshot = yield call(captureFilterContextByTabSnapshot);
224
+ const session = yield call(beginTabSync, { tabLocalIdentifier });
221
225
  // Ensure display form metadata is loaded for filters that will actually be applied.
222
226
  // This handles the case where a default saved view changed filter types (e.g., list→text)
223
227
  // and then local storage restores original types whose display forms weren't loaded during init.
@@ -229,18 +233,13 @@ export function* changeFilterContextSelectionHandler(ctx, cmd) {
229
233
  }
230
234
  }
231
235
  }
232
- yield put(batchActions(markRestoreTargetOriginal([
236
+ yield call(putTabSynced, session, markRestoreTargetOriginal([
233
237
  ...attributeFilterResult.actions,
234
238
  ...commonDateFilterUpdateActions,
235
239
  ...dateFiltersUpdateActions,
236
240
  ...measureValueFilterUpdateActions,
237
- ], restorePerTabOriginals)));
238
- if (enablePersistentFiltersAcrossTabs) {
239
- yield call(dispatchFilterContextChangedForMutatedTabs, ctx, cmd, filterContextSnapshot);
240
- }
241
- else {
242
- yield call(dispatchFilterContextChanged, ctx, cmd, tabLocalIdentifier);
243
- }
241
+ ], restorePerTabOriginals));
242
+ yield call(endTabSync, ctx, cmd, session, tabLocalIdentifier);
244
243
  }
245
244
  function* getDashboardFilterByAttributeMatching(filterRef, resolvedDisplayForms, ctx, tabLocalIdentifier, isFilterExcluded, areDisplayFormsEquivalent = areObjRefsEqual) {
246
245
  if (isUriRef(filterRef) && !ctx.backend.capabilities.supportsObjectUris) {
@@ -326,9 +325,7 @@ function* getAttributeFiltersUpdateActions(attributeFilters, textAttributeFilter
326
325
  const updateActions = [];
327
326
  const displayFormsToResolve = [];
328
327
  const handledLocalIds = new Set();
329
- const crossFilteringLocalIdsByTab = yield select(selectCrossFilteringFiltersLocalIdentifiersByTab);
330
328
  const resolvedDisplayForms = yield call(resolveDisplayFormMetadata, ctx, attributeFilters.map((af) => dashboardAttributeFilterItemDisplayForm(af)));
331
- const enablePersistentFiltersAcrossTabs = yield select(selectEnablePersistentFiltersAcrossTabs);
332
329
  // A payload can give a display form as a URI ref, and the dashboard can store it as an
333
330
  // identifier ref. The two refs are equal when they point to the same display form metadata.
334
331
  const displayFormsMap = yield select(selectAttributeFilterDisplayFormsMap);
@@ -483,8 +480,6 @@ function* getAttributeFiltersUpdateActions(attributeFilters, textAttributeFilter
483
480
  updateActions.push(tabsActions.updateAttributeFilterSelection({
484
481
  ...getAttributeFilterSelectionPayload(attributeFilter, dashboardFilter),
485
482
  tabLocalIdentifier,
486
- crossFilteringLocalIdsByTab,
487
- enablePersistentFiltersAcrossTabs,
488
483
  }));
489
484
  handledLocalIds.add(dashboardFilterLocalId);
490
485
  }
@@ -529,8 +524,6 @@ function* getAttributeFiltersUpdateActions(attributeFilters, textAttributeFilter
529
524
  filterLocalId: targetLocalId,
530
525
  filter: normalizedListFilter,
531
526
  tabLocalIdentifier,
532
- crossFilteringLocalIdsByTab,
533
- enablePersistentFiltersAcrossTabs,
534
527
  }), tabsActions.changeDisplayAsLabel({
535
528
  localIdentifier: targetLocalId,
536
529
  displayAsLabel: dashboardAttributeFilterItemDisplayForm(targetTextFilter),
@@ -588,8 +581,6 @@ function* getAttributeFiltersUpdateActions(attributeFilters, textAttributeFilter
588
581
  filterLocalId: targetLocalId,
589
582
  filter: normalizedTextFilter,
590
583
  tabLocalIdentifier,
591
- crossFilteringLocalIdsByTab,
592
- enablePersistentFiltersAcrossTabs,
593
584
  }));
594
585
  const textDisplayForm = dashboardAttributeFilterItemDisplayForm(textFilter);
595
586
  // List → text: update displayAsLabel to match the text filter's displayForm
@@ -613,8 +604,6 @@ function* getAttributeFiltersUpdateActions(attributeFilters, textAttributeFilter
613
604
  updateActions.push(tabsActions.clearAttributeFiltersSelection({
614
605
  filterLocalIds: unhandledFilters.map((filter) => dashboardAttributeFilterItemLocalIdentifier(filter)),
615
606
  tabLocalIdentifier,
616
- crossFilteringLocalIdsByTab,
617
- enablePersistentFiltersAcrossTabs,
618
607
  }));
619
608
  }
620
609
  // for text filters (arbitrary/match) that have not been handled, reset to All state
@@ -639,15 +628,12 @@ function* getAttributeFiltersUpdateActions(attributeFilters, textAttributeFilter
639
628
  filterLocalId: localId,
640
629
  filter: resetFilter,
641
630
  tabLocalIdentifier,
642
- crossFilteringLocalIdsByTab,
643
- enablePersistentFiltersAcrossTabs,
644
631
  }));
645
632
  }
646
633
  }
647
634
  return { actions: updateActions, displayFormsToResolve };
648
635
  }
649
636
  function* getDateFilterUpdateActions(dateFilter, resetOthers, tabLocalIdentifier) {
650
- const enablePersistentFiltersAcrossTabs = yield select(selectEnablePersistentFiltersAcrossTabs);
651
637
  if (dateFilter) {
652
638
  const canApply = yield call(canApplyDateFilter, dateFilter);
653
639
  if (!canApply) {
@@ -666,7 +652,6 @@ function* getDateFilterUpdateActions(dateFilter, resetOthers, tabLocalIdentifier
666
652
  ...localIdentifierObj,
667
653
  ...emptyValueHandlingObj,
668
654
  tabLocalIdentifier,
669
- enablePersistentFiltersAcrossTabs,
670
655
  }
671
656
  : {
672
657
  type: dateFilter.dateFilter.type,
@@ -680,7 +665,6 @@ function* getDateFilterUpdateActions(dateFilter, resetOthers, tabLocalIdentifier
680
665
  : {}),
681
666
  ...emptyValueHandlingObj,
682
667
  tabLocalIdentifier,
683
- enablePersistentFiltersAcrossTabs,
684
668
  };
685
669
  return [tabsActions.upsertDateFilter(upsertPayload)];
686
670
  }
@@ -689,21 +673,19 @@ function* getDateFilterUpdateActions(dateFilter, resetOthers, tabLocalIdentifier
689
673
  tabsActions.upsertDateFilter({
690
674
  type: "allTime",
691
675
  tabLocalIdentifier,
692
- enablePersistentFiltersAcrossTabs,
693
676
  }),
694
677
  ];
695
678
  }
696
679
  return [];
697
680
  }
698
- function* getMeasureValueFiltersUpdateActions(measureValueFilters, resetOthers) {
681
+ function* getMeasureValueFiltersUpdateActions(measureValueFilters, resetOthers, tabLocalIdentifier) {
699
682
  const updateActions = [];
700
683
  const handledLocalIds = new Set();
701
684
  // a restricted filter keeps its stored conditions: it is neither matched nor reset
702
- const allMeasureValueFilters = yield select(selectFilterContextMeasureValueFilters);
703
- const restrictedLocalIdentifiers = yield select(selectRestrictedDashboardFilterLocalIdentifiers);
685
+ const allMeasureValueFilters = yield call(selectFilterContextMeasureValueFiltersTabAware, tabLocalIdentifier);
686
+ const restrictedLocalIdentifiers = yield call(selectRestrictedDashboardFilterLocalIdentifiersTabAware, tabLocalIdentifier);
704
687
  const currentMeasureValueFilters = allMeasureValueFilters.filter((filter) => !restrictedLocalIdentifiers.has(dashboardMeasureValueFilterLocalIdentifier(filter)));
705
688
  const currentByLocalId = new Map(currentMeasureValueFilters.map((f) => [dashboardMeasureValueFilterLocalIdentifier(f), f]));
706
- const enablePersistentFiltersAcrossTabs = yield select(selectEnablePersistentFiltersAcrossTabs);
707
689
  for (const incoming of measureValueFilters) {
708
690
  const incomingLocalIdentifier = dashboardMeasureValueFilterLocalIdentifier(incoming);
709
691
  const currentFilter = currentByLocalId.get(incomingLocalIdentifier) ??
@@ -719,13 +701,13 @@ function* getMeasureValueFiltersUpdateActions(measureValueFilters, resetOthers)
719
701
  updateActions.push(tabsActions.changeMeasureValueFilterCondition({
720
702
  localIdentifier,
721
703
  conditions: incoming.dashboardMeasureValueFilter.conditions,
722
- enablePersistentFiltersAcrossTabs,
704
+ tabLocalIdentifier,
723
705
  }));
724
706
  if ("dimensionality" in incoming.dashboardMeasureValueFilter) {
725
707
  updateActions.push(tabsActions.setMeasureValueFilterDimensionality({
726
708
  localIdentifier,
727
709
  dimensionality: incoming.dashboardMeasureValueFilter.dimensionality,
728
- enablePersistentFiltersAcrossTabs,
710
+ tabLocalIdentifier,
729
711
  }));
730
712
  }
731
713
  }
@@ -740,7 +722,7 @@ function* getMeasureValueFiltersUpdateActions(measureValueFilters, resetOthers)
740
722
  updateActions.push(tabsActions.changeMeasureValueFilterCondition({
741
723
  localIdentifier,
742
724
  conditions: undefined,
743
- enablePersistentFiltersAcrossTabs,
725
+ tabLocalIdentifier,
744
726
  }));
745
727
  }
746
728
  }
@@ -749,7 +731,6 @@ function* getMeasureValueFiltersUpdateActions(measureValueFilters, resetOthers)
749
731
  function* getDateFiltersUpdateActions(dateFilters, resetOthers, tabLocalIdentifier) {
750
732
  const updateActions = [];
751
733
  const handledDataSets = new Set();
752
- const enablePersistentFiltersAcrossTabs = yield select(selectEnablePersistentFiltersAcrossTabs);
753
734
  for (const dateFilter of dateFilters) {
754
735
  const filterRef = dateFilter.dateFilter.dataSet;
755
736
  const dashboardFilter = yield call(selectFilterContextDateFilterByDataSetTabAware, filterRef, tabLocalIdentifier);
@@ -768,7 +749,6 @@ function* getDateFiltersUpdateActions(dateFilters, resetOthers, tabLocalIdentifi
768
749
  ...localIdentifierObj,
769
750
  ...emptyValueHandlingObj,
770
751
  tabLocalIdentifier,
771
- enablePersistentFiltersAcrossTabs,
772
752
  }
773
753
  : {
774
754
  type: dateFilter.dateFilter.type,
@@ -782,7 +762,6 @@ function* getDateFiltersUpdateActions(dateFilters, resetOthers, tabLocalIdentifi
782
762
  : {}),
783
763
  ...emptyValueHandlingObj,
784
764
  tabLocalIdentifier,
785
- enablePersistentFiltersAcrossTabs,
786
765
  };
787
766
  updateActions.push(tabsActions.upsertDateFilter(upsertPayload));
788
767
  }
@@ -801,7 +780,6 @@ function* getDateFiltersUpdateActions(dateFilters, resetOthers, tabLocalIdentifi
801
780
  dataSet: dateFilter.dateFilter.dataSet,
802
781
  ...localIdentifierObj,
803
782
  tabLocalIdentifier,
804
- enablePersistentFiltersAcrossTabs,
805
783
  }));
806
784
  }
807
785
  }
@@ -3,6 +3,7 @@ import { type IDashboardAttributeFilterConfig, type IDashboardDateFilter, type I
3
3
  import { type IDashboardCommand } from "../../commands/base.js";
4
4
  import { type IWorkingFilterContextDefinition } from "../../store/tabs/filterContext/filterContextState.js";
5
5
  import { type DashboardContext } from "../../types/commonTypes.js";
6
+ import { type ITabSyncSession } from "./tabSync/tabSyncSaga.js";
6
7
  /**
7
8
  * Applied filter context and attribute filter configs of every tab, taken before a write.
8
9
  * Compared with the store afterwards so a mirrored change emits one event per tab updated.
@@ -13,17 +14,17 @@ export interface IFilterContextByTabSnapshot {
13
14
  readonly attributeFilterConfigs: Record<string, IDashboardAttributeFilterConfig[]>;
14
15
  }
15
16
  export declare function captureFilterContextByTabSnapshot(): SagaIterator<IFilterContextByTabSnapshot>;
16
- export declare function dispatchFilterContextChangedForMutatedTabs(ctx: DashboardContext, cmd: IDashboardCommand, snapshot: IFilterContextByTabSnapshot): SagaIterator<void>;
17
+ /**
18
+ * Emits a filter context changed event for every tab that differs from `snapshot`, except `skippedTabId`.
19
+ */
20
+ export declare function dispatchFilterContextChangedForMutatedTabs(ctx: DashboardContext, cmd: IDashboardCommand, snapshot: IFilterContextByTabSnapshot, skippedTabId?: string): SagaIterator<void>;
17
21
  export declare function dispatchFilterContextChanged(ctx: DashboardContext, cmd: IDashboardCommand, tabLocalIdentifier?: string): SagaIterator<void>;
18
22
  export declare function canApplyDateFilter(dateFilter: IDashboardDateFilter): SagaIterator<boolean>;
19
23
  export declare function resetCrossFiltering(cmd: IDashboardCommand): Generator<import("redux-saga/effects").PutEffect<import("../../commands/filters.js").IRemoveAttributeFilters> | import("redux-saga/effects").PutEffect<{
20
24
  payload: string | undefined;
21
25
  type: "drill/resetCrossFiltering";
22
26
  }> | import("redux-saga/effects").SelectEffect, void, string[] & string>;
23
- export declare function applyWorkingSelectionHandler(ctx: DashboardContext, cmd: IDashboardCommand): Generator<import("redux-saga/effects").CallEffect<void> | import("redux-saga/effects").CallEffect<IFilterContextByTabSnapshot> | import("redux-saga/effects").PutEffect<{
24
- payload: import("../../../index.js").IApplyWorkingSelectionPayload;
25
- type: "tabs/applyWorkingSelection";
26
- }> | import("redux-saga/effects").PutEffect<import("../../events/base.js").ICustomDashboardEvent<any> | import("../../events/base.js").IDashboardEvent<any>> | import("redux-saga/effects").SelectEffect, void, never>;
27
+ export declare function applyWorkingSelectionHandler(ctx: DashboardContext, cmd: IDashboardCommand): Generator<import("redux-saga/effects").CallEffect<void> | import("redux-saga/effects").CallEffect<import("redux").Action[]> | import("redux-saga/effects").CallEffect<ITabSyncSession> | import("redux-saga/effects").PutEffect<import("../../events/base.js").ICustomDashboardEvent<any> | import("../../events/base.js").IDashboardEvent<any>> | import("redux-saga/effects").SelectEffect, void, never>;
27
28
  export declare function resetWorkingSelectionHandler(): Generator<import("redux-saga/effects").PutEffect<{
28
29
  payload: undefined;
29
30
  type: "tabs/resetWorkingSelection";
@@ -1 +1 @@
1
- {"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../../../../src/model/commandHandlers/filterContext/common.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAI/C,OAAO,EACH,KAAK,+BAA+B,EACpC,KAAK,oBAAoB,EACzB,KAAK,wBAAwB,EAChC,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAuBhE,OAAO,EAAE,KAAK,+BAA+B,EAAE,MAAM,sDAAsD,CAAC;AAI5G,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAGnE;;;GAGG;AACH,MAAM,WAAW,2BAA2B;IACxC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,wBAAwB,GAAG,SAAS,CAAC,CAAC;IAC9E,QAAQ,CAAC,qBAAqB,EAAE,MAAM,CAAC,MAAM,EAAE,+BAA+B,GAAG,SAAS,CAAC,CAAC;IAC5F,QAAQ,CAAC,sBAAsB,EAAE,MAAM,CAAC,MAAM,EAAE,+BAA+B,EAAE,CAAC,CAAC;CACtF;AAED,wBAAiB,iCAAiC,IAAI,YAAY,CAAC,2BAA2B,CAAC,CAU9F;AAED,wBAAiB,0CAA0C,CACvD,GAAG,EAAE,gBAAgB,EACrB,GAAG,EAAE,iBAAiB,EACtB,QAAQ,EAAE,2BAA2B,GACtC,YAAY,CAAC,IAAI,CAAC,CAwBpB;AAED,wBAAiB,4BAA4B,CACzC,GAAG,EAAE,gBAAgB,EACrB,GAAG,EAAE,iBAAiB,EACtB,kBAAkB,CAAC,EAAE,MAAM,GAC5B,YAAY,CAAC,IAAI,CAAC,CAkCpB;AAED,wBAAiB,kBAAkB,CAAC,UAAU,EAAE,oBAAoB,GAAG,YAAY,CAAC,OAAO,CAAC,CAuB3F;AAED,wBAAiB,mBAAmB,CAAC,GAAG,EAAE,iBAAiB;;;yEAU1D;AAED,wBAAiB,4BAA4B,CAAC,GAAG,EAAE,gBAAgB,EAAE,GAAG,EAAE,iBAAiB;;;uNAwC1F;AAED,wBAAiB,4BAA4B;;;mBAE5C"}
1
+ {"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../../../../src/model/commandHandlers/filterContext/common.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAI/C,OAAO,EACH,KAAK,+BAA+B,EACpC,KAAK,oBAAoB,EACzB,KAAK,wBAAwB,EAChC,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAqBhE,OAAO,EAAE,KAAK,+BAA+B,EAAE,MAAM,sDAAsD,CAAC;AAI5G,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAGnE,OAAO,EAAE,KAAK,eAAe,EAA0C,MAAM,0BAA0B,CAAC;AAExG;;;GAGG;AACH,MAAM,WAAW,2BAA2B;IACxC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,wBAAwB,GAAG,SAAS,CAAC,CAAC;IAC9E,QAAQ,CAAC,qBAAqB,EAAE,MAAM,CAAC,MAAM,EAAE,+BAA+B,GAAG,SAAS,CAAC,CAAC;IAC5F,QAAQ,CAAC,sBAAsB,EAAE,MAAM,CAAC,MAAM,EAAE,+BAA+B,EAAE,CAAC,CAAC;CACtF;AAED,wBAAiB,iCAAiC,IAAI,YAAY,CAAC,2BAA2B,CAAC,CAU9F;AAED;;GAEG;AACH,wBAAiB,0CAA0C,CACvD,GAAG,EAAE,gBAAgB,EACrB,GAAG,EAAE,iBAAiB,EACtB,QAAQ,EAAE,2BAA2B,EACrC,YAAY,CAAC,EAAE,MAAM,GACtB,YAAY,CAAC,IAAI,CAAC,CAwBpB;AAED,wBAAiB,4BAA4B,CACzC,GAAG,EAAE,gBAAgB,EACrB,GAAG,EAAE,iBAAiB,EACtB,kBAAkB,CAAC,EAAE,MAAM,GAC5B,YAAY,CAAC,IAAI,CAAC,CAkCpB;AAED,wBAAiB,kBAAkB,CAAC,UAAU,EAAE,oBAAoB,GAAG,YAAY,CAAC,OAAO,CAAC,CAuB3F;AAED,wBAAiB,mBAAmB,CAAC,GAAG,EAAE,iBAAiB;;;yEAU1D;AAED,wBAAiB,4BAA4B,CAAC,GAAG,EAAE,gBAAgB,EAAE,GAAG,EAAE,iBAAiB,8YA4B1F;AAED,wBAAiB,4BAA4B;;;mBAE5C"}
@@ -7,9 +7,8 @@ import { removeAttributeFilters } from "../../commands/filters.js";
7
7
  import { filterContextChanged, filterContextWorkingSelectionApplied } from "../../events/filters.js";
8
8
  import { dispatchDashboardEvent } from "../../store/_infra/eventDispatcher.js";
9
9
  import { selectEnableImmediateAttributeFilterDisplayAsLabelMigration } from "../../store/config/configSelectors.js";
10
- import { selectCrossFilteringFiltersLocalIdentifiers, selectCrossFilteringFiltersLocalIdentifiersByTab, selectIsCrossFiltering, } from "../../store/drill/drillSelectors.js";
10
+ import { selectCrossFilteringFiltersLocalIdentifiers, selectIsCrossFiltering, } from "../../store/drill/drillSelectors.js";
11
11
  import { drillActions } from "../../store/drill/index.js";
12
- import { selectEnablePersistentFiltersAcrossTabs } from "../../store/meta/metaSelectors.js";
13
12
  import { selectAttributeFilterConfigsOverrides, selectAttributeFilterConfigsOverridesByTab, } from "../../store/tabs/attributeFilterConfigs/attributeFilterConfigsSelectors.js";
14
13
  import { selectEffectiveDateFilterOptions } from "../../store/tabs/dateFilterConfig/dateFilterConfigSelectors.js";
15
14
  import { selectFilterContextDefinition, selectFilterContextDefinitionsByTab, selectIsWorkingFilterContextChanged, selectWorkingFilterContextDefinitionsByTab, } from "../../store/tabs/filterContext/filterContextSelectors.js";
@@ -17,18 +16,22 @@ import { tabsActions } from "../../store/tabs/index.js";
17
16
  import { selectParameterValuesByTab } from "../../store/tabs/parameters/parametersSelectors.js";
18
17
  import { selectActiveOrDefaultTabLocalIdentifier } from "../../store/tabs/tabsSelectors.js";
19
18
  import { dispatchParametersChangedForAffectedTabs } from "../parameters/changeParameterValuesHandler.js";
19
+ import { beginTabSync, endTabSync, putTabSynced } from "./tabSync/tabSyncSaga.js";
20
20
  export function* captureFilterContextByTabSnapshot() {
21
21
  const filterContexts = yield select(selectFilterContextDefinitionsByTab);
22
22
  const workingFilterContexts = yield select(selectWorkingFilterContextDefinitionsByTab);
23
23
  const attributeFilterConfigs = yield select(selectAttributeFilterConfigsOverridesByTab);
24
24
  return { filterContexts, workingFilterContexts, attributeFilterConfigs };
25
25
  }
26
- export function* dispatchFilterContextChangedForMutatedTabs(ctx, cmd, snapshot) {
26
+ /**
27
+ * Emits a filter context changed event for every tab that differs from `snapshot`, except `skippedTabId`.
28
+ */
29
+ export function* dispatchFilterContextChangedForMutatedTabs(ctx, cmd, snapshot, skippedTabId) {
27
30
  const filterContexts = yield select(selectFilterContextDefinitionsByTab);
28
31
  const attributeFilterConfigs = yield select(selectAttributeFilterConfigsOverridesByTab);
29
32
  const workingFilterContexts = yield select(selectWorkingFilterContextDefinitionsByTab);
30
33
  for (const tabId of Object.keys(filterContexts)) {
31
- if (!filterContexts[tabId]) {
34
+ if (!filterContexts[tabId] || tabId === skippedTabId) {
32
35
  continue;
33
36
  }
34
37
  const configs = attributeFilterConfigs[tabId] ?? [];
@@ -89,25 +92,16 @@ export function* applyWorkingSelectionHandler(ctx, cmd) {
89
92
  const isWorkingFilterContextChanged = yield select(selectIsWorkingFilterContextChanged);
90
93
  const tabId = yield select(selectActiveOrDefaultTabLocalIdentifier);
91
94
  const valuesBefore = yield select(selectParameterValuesByTab);
92
- const crossFilteringLocalIdsByTab = yield select(selectCrossFilteringFiltersLocalIdentifiersByTab);
93
- const enablePersistentFiltersAcrossTabs = yield select(selectEnablePersistentFiltersAcrossTabs);
94
- const filterContextSnapshot = yield call(captureFilterContextByTabSnapshot);
95
- yield put(tabsActions.applyWorkingSelection({
96
- enableImmediateAttributeFilterDisplayAsLabelMigration,
97
- crossFilteringLocalIdsByTab,
98
- enablePersistentFiltersAcrossTabs,
99
- }));
95
+ const session = yield call(beginTabSync);
96
+ yield call(putTabSynced, session, [
97
+ tabsActions.applyWorkingSelection({ enableImmediateAttributeFilterDisplayAsLabelMigration }),
98
+ ]);
100
99
  const isCrossFiltering = yield select(selectIsCrossFiltering);
101
100
  if (isWorkingFilterContextChanged && isCrossFiltering) {
102
101
  yield call(resetCrossFiltering, cmd);
103
102
  }
104
103
  yield dispatchDashboardEvent(filterContextWorkingSelectionApplied(ctx, cmd.correlationId));
105
- if (enablePersistentFiltersAcrossTabs) {
106
- yield call(dispatchFilterContextChangedForMutatedTabs, ctx, cmd, filterContextSnapshot);
107
- }
108
- else {
109
- yield call(dispatchFilterContextChanged, ctx, cmd);
110
- }
104
+ yield call(endTabSync, ctx, cmd, session);
111
105
  yield call(dispatchParametersChangedForAffectedTabs, ctx, cmd, valuesBefore, tabId);
112
106
  }
113
107
  export function* resetWorkingSelectionHandler() {
@@ -1 +1 @@
1
- {"version":3,"file":"changeDateFilterSelectionHandler.d.ts","sourceRoot":"","sources":["../../../../../src/model/commandHandlers/filterContext/dateFilter/changeDateFilterSelectionHandler.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAU/C,OAAO,EAAE,KAAK,yBAAyB,EAA4B,MAAM,8BAA8B,CAAC;AAYxG,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAUtE,wBAAiB,gCAAgC,CAC7C,GAAG,EAAE,gBAAgB,EACrB,GAAG,EAAE,yBAAyB,GAC/B,YAAY,CAAC,IAAI,CAAC,CA8EpB"}
1
+ {"version":3,"file":"changeDateFilterSelectionHandler.d.ts","sourceRoot":"","sources":["../../../../../src/model/commandHandlers/filterContext/dateFilter/changeDateFilterSelectionHandler.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAU/C,OAAO,EAAE,KAAK,yBAAyB,EAA4B,MAAM,8BAA8B,CAAC;AAWxG,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAItE,wBAAiB,gCAAgC,CAC7C,GAAG,EAAE,gBAAgB,EACrB,GAAG,EAAE,yBAAyB,GAC/B,YAAY,CAAC,IAAI,CAAC,CAsEpB"}
@@ -1,16 +1,16 @@
1
1
  // (C) 2021-2026 GoodData Corporation
2
2
  import { toNumber } from "lodash-es";
3
- import { call, put, select } from "redux-saga/effects";
3
+ import { call, select } from "redux-saga/effects";
4
4
  import { newAbsoluteDashboardDateFilter, newAllTimeDashboardDateFilter, newRelativeDashboardDateFilter, } from "@gooddata/sdk-model";
5
5
  import { dateFilterChanged } from "../../../events/filters.js";
6
6
  import { invalidArgumentsProvided } from "../../../events/general.js";
7
7
  import { dispatchDashboardEvent } from "../../../store/_infra/eventDispatcher.js";
8
8
  import { selectIsApplyFiltersAllAtOnceEnabledAndSet } from "../../../store/config/configSelectors.js";
9
9
  import { selectIsCrossFiltering } from "../../../store/drill/drillSelectors.js";
10
- import { selectEnablePersistentFiltersAcrossTabs } from "../../../store/meta/metaSelectors.js";
11
10
  import { selectFilterContextDateFilter, selectFilterContextDateFilterByDataSet, } from "../../../store/tabs/filterContext/filterContextSelectors.js";
12
11
  import { tabsActions } from "../../../store/tabs/index.js";
13
- import { canApplyDateFilter, captureFilterContextByTabSnapshot, dispatchFilterContextChanged, dispatchFilterContextChangedForMutatedTabs, resetCrossFiltering, } from "../common.js";
12
+ import { canApplyDateFilter, resetCrossFiltering } from "../common.js";
13
+ import { beginTabSync, endTabSync, putTabSynced } from "../tabSync/tabSyncSaga.js";
14
14
  export function* changeDateFilterSelectionHandler(ctx, cmd) {
15
15
  const isAllTime = cmd.payload.type === "relative" &&
16
16
  cmd.payload.granularity === "GDC.time.date" &&
@@ -20,38 +20,37 @@ export function* changeDateFilterSelectionHandler(ctx, cmd) {
20
20
  if (!canApply) {
21
21
  throw invalidArgumentsProvided(ctx, cmd, `Cannot apply a date filter that is invalid by the current dateFilterConfig.`);
22
22
  }
23
- const filterContextSnapshot = yield call(captureFilterContextByTabSnapshot);
24
- const enablePersistentFiltersAcrossTabs = yield select(selectEnablePersistentFiltersAcrossTabs);
23
+ const session = yield call(beginTabSync);
25
24
  const isApplyAllAtOnceEnabledAndSet = yield select(selectIsApplyFiltersAllAtOnceEnabledAndSet);
26
25
  const isWorkingSelectionChange = cmd.payload.isWorkingSelectionChange && isApplyAllAtOnceEnabledAndSet;
27
26
  const localIdentifierObj = cmd.payload.localIdentifier
28
27
  ? { localIdentifier: cmd.payload.localIdentifier }
29
28
  : {};
30
- yield put(tabsActions.upsertDateFilter(isAllTime
31
- ? {
32
- type: "allTime",
33
- dataSet: cmd.payload.dataSet,
34
- isWorkingSelectionChange,
35
- enablePersistentFiltersAcrossTabs,
36
- ...localIdentifierObj,
37
- ...(cmd.payload.emptyValueHandling
38
- ? { emptyValueHandling: cmd.payload.emptyValueHandling }
39
- : {}),
40
- }
41
- : {
42
- type: cmd.payload.type,
43
- granularity: cmd.payload.granularity,
44
- from: cmd.payload.from,
45
- to: cmd.payload.to,
46
- dataSet: cmd.payload.dataSet,
47
- isWorkingSelectionChange,
48
- enablePersistentFiltersAcrossTabs,
49
- ...localIdentifierObj,
50
- ...(cmd.payload.boundedFilter ? { boundedFilter: cmd.payload.boundedFilter } : {}),
51
- ...(cmd.payload.emptyValueHandling
52
- ? { emptyValueHandling: cmd.payload.emptyValueHandling }
53
- : {}),
54
- }));
29
+ yield call(putTabSynced, session, [
30
+ tabsActions.upsertDateFilter(isAllTime
31
+ ? {
32
+ type: "allTime",
33
+ dataSet: cmd.payload.dataSet,
34
+ isWorkingSelectionChange,
35
+ ...localIdentifierObj,
36
+ ...(cmd.payload.emptyValueHandling
37
+ ? { emptyValueHandling: cmd.payload.emptyValueHandling }
38
+ : {}),
39
+ }
40
+ : {
41
+ type: cmd.payload.type,
42
+ granularity: cmd.payload.granularity,
43
+ from: cmd.payload.from,
44
+ to: cmd.payload.to,
45
+ dataSet: cmd.payload.dataSet,
46
+ isWorkingSelectionChange,
47
+ ...localIdentifierObj,
48
+ ...(cmd.payload.boundedFilter ? { boundedFilter: cmd.payload.boundedFilter } : {}),
49
+ ...(cmd.payload.emptyValueHandling
50
+ ? { emptyValueHandling: cmd.payload.emptyValueHandling }
51
+ : {}),
52
+ }),
53
+ ]);
55
54
  if (!isWorkingSelectionChange) {
56
55
  const isCrossFiltering = yield select(selectIsCrossFiltering);
57
56
  if (isCrossFiltering) {
@@ -62,12 +61,7 @@ export function* changeDateFilterSelectionHandler(ctx, cmd) {
62
61
  ? yield select(selectFilterContextDateFilterByDataSet(cmd.payload.dataSet))
63
62
  : yield select(selectFilterContextDateFilter);
64
63
  yield dispatchDashboardEvent(dateFilterChanged(ctx, affectedFilter, cmd.payload.dateFilterOptionLocalId, cmd.correlationId));
65
- if (enablePersistentFiltersAcrossTabs) {
66
- yield call(dispatchFilterContextChangedForMutatedTabs, ctx, cmd, filterContextSnapshot);
67
- }
68
- else {
69
- yield call(dispatchFilterContextChanged, ctx, cmd);
70
- }
64
+ yield call(endTabSync, ctx, cmd, session);
71
65
  }
72
66
  function dateFilterSelectionToDateFilter(dateFilterSelection) {
73
67
  if (dateFilterSelection.type === "absolute" && dateFilterSelection.from && dateFilterSelection.to) {
@@ -1 +1 @@
1
- {"version":3,"file":"changeMeasureValueFilterConditionHandler.d.ts","sourceRoot":"","sources":["../../../../../src/model/commandHandlers/filterContext/measureValueFilter/changeMeasureValueFilterConditionHandler.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAI/C,OAAO,EAAE,KAAK,kCAAkC,EAAE,MAAM,8BAA8B,CAAC;AAUvF,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAQtE,wBAAiB,wCAAwC,CACrD,GAAG,EAAE,gBAAgB,EACrB,GAAG,EAAE,kCAAkC,GACxC,YAAY,CAAC,IAAI,CAAC,CAmDpB"}
1
+ {"version":3,"file":"changeMeasureValueFilterConditionHandler.d.ts","sourceRoot":"","sources":["../../../../../src/model/commandHandlers/filterContext/measureValueFilter/changeMeasureValueFilterConditionHandler.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAI/C,OAAO,EAAE,KAAK,kCAAkC,EAAE,MAAM,8BAA8B,CAAC;AASvF,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAGtE,wBAAiB,wCAAwC,CACrD,GAAG,EAAE,gBAAgB,EACrB,GAAG,EAAE,kCAAkC,GACxC,YAAY,CAAC,IAAI,CAAC,CA2CpB"}