@gooddata/sdk-ui-dashboard 11.67.0-alpha.3 → 11.67.0-alpha.4

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 (113) hide show
  1. package/NOTICE +16 -233
  2. package/esm/__version.d.ts +1 -1
  3. package/esm/__version.js +1 -1
  4. package/esm/model/commandHandlers/dashboard/changeDashboardDefinitionHandler.d.ts.map +1 -1
  5. package/esm/model/commandHandlers/dashboard/changeDashboardDefinitionHandler.js +3 -1
  6. package/esm/model/commandHandlers/dashboard/common/filterViews.js +10 -3
  7. package/esm/model/commandHandlers/dashboard/common/overrideFiltersAcrossTabs.d.ts +46 -0
  8. package/esm/model/commandHandlers/dashboard/common/overrideFiltersAcrossTabs.d.ts.map +1 -0
  9. package/esm/model/commandHandlers/dashboard/common/overrideFiltersAcrossTabs.js +155 -0
  10. package/esm/model/commandHandlers/dashboard/common/stateInitializers.d.ts +4 -2
  11. package/esm/model/commandHandlers/dashboard/common/stateInitializers.d.ts.map +1 -1
  12. package/esm/model/commandHandlers/dashboard/common/stateInitializers.js +14 -10
  13. package/esm/model/commandHandlers/dashboard/initializeDashboardHandler/index.d.ts.map +1 -1
  14. package/esm/model/commandHandlers/dashboard/initializeDashboardHandler/index.js +9 -5
  15. package/esm/model/commandHandlers/dashboard/resetDashboardHandler.js +1 -1
  16. package/esm/model/commandHandlers/drill/common/mergeFilters.js +2 -2
  17. package/esm/model/commandHandlers/filterContext/tabSync/tabSyncRules.d.ts.map +1 -1
  18. package/esm/model/commandHandlers/filterContext/tabSync/tabSyncRules.js +114 -23
  19. package/esm/model/commandHandlers/parameters/loadParameterDependencies.d.ts +1 -1
  20. package/esm/model/commandHandlers/parameters/loadParameterDependencies.js +1 -1
  21. package/esm/model/commandHandlers/tabs/createDashboardTabHandler.d.ts.map +1 -1
  22. package/esm/model/commandHandlers/tabs/createDashboardTabHandler.js +3 -27
  23. package/esm/model/store/tabs/filterContext/filterSync.d.ts +6 -22
  24. package/esm/model/store/tabs/filterContext/filterSync.d.ts.map +1 -1
  25. package/esm/model/store/tabs/filterContext/filterSync.js +42 -40
  26. package/esm/model/types/commonTypes.d.ts +3 -0
  27. package/esm/model/types/commonTypes.d.ts.map +1 -1
  28. package/esm/presentation/automations/shared/automationFilters/automationParameters.d.ts +3 -3
  29. package/esm/presentation/automations/shared/automationFilters/automationParameters.js +3 -3
  30. package/esm/presentation/automations/shared/automationFilters/useAutomationAlertParameters.d.ts +1 -1
  31. package/esm/presentation/automations/shared/automationFilters/useAutomationAlertParameters.js +1 -1
  32. package/esm/presentation/dashboard/components/DensityInitializer.d.ts +1 -1
  33. package/esm/presentation/dashboard/components/DensityInitializer.js +1 -1
  34. package/esm/presentation/filterBar/measureValueFilter/useDashboardMeasureValueFilterData.d.ts +1 -1
  35. package/esm/presentation/localization/bundles/de-DE.localization-bundle.d.ts +0 -2
  36. package/esm/presentation/localization/bundles/de-DE.localization-bundle.d.ts.map +1 -1
  37. package/esm/presentation/localization/bundles/de-DE.localization-bundle.js +0 -2
  38. package/esm/presentation/localization/bundles/en-AU.localization-bundle.d.ts +0 -2
  39. package/esm/presentation/localization/bundles/en-AU.localization-bundle.d.ts.map +1 -1
  40. package/esm/presentation/localization/bundles/en-AU.localization-bundle.js +0 -2
  41. package/esm/presentation/localization/bundles/en-GB.localization-bundle.d.ts +0 -2
  42. package/esm/presentation/localization/bundles/en-GB.localization-bundle.d.ts.map +1 -1
  43. package/esm/presentation/localization/bundles/en-GB.localization-bundle.js +0 -2
  44. package/esm/presentation/localization/bundles/es-419.localization-bundle.d.ts +0 -2
  45. package/esm/presentation/localization/bundles/es-419.localization-bundle.d.ts.map +1 -1
  46. package/esm/presentation/localization/bundles/es-419.localization-bundle.js +0 -2
  47. package/esm/presentation/localization/bundles/es-ES.localization-bundle.d.ts +0 -2
  48. package/esm/presentation/localization/bundles/es-ES.localization-bundle.d.ts.map +1 -1
  49. package/esm/presentation/localization/bundles/es-ES.localization-bundle.js +0 -2
  50. package/esm/presentation/localization/bundles/fi-FI.localization-bundle.d.ts +0 -2
  51. package/esm/presentation/localization/bundles/fi-FI.localization-bundle.d.ts.map +1 -1
  52. package/esm/presentation/localization/bundles/fi-FI.localization-bundle.js +0 -2
  53. package/esm/presentation/localization/bundles/fr-CA.localization-bundle.d.ts +0 -2
  54. package/esm/presentation/localization/bundles/fr-CA.localization-bundle.d.ts.map +1 -1
  55. package/esm/presentation/localization/bundles/fr-CA.localization-bundle.js +0 -2
  56. package/esm/presentation/localization/bundles/fr-FR.localization-bundle.d.ts +0 -2
  57. package/esm/presentation/localization/bundles/fr-FR.localization-bundle.d.ts.map +1 -1
  58. package/esm/presentation/localization/bundles/fr-FR.localization-bundle.js +0 -2
  59. package/esm/presentation/localization/bundles/id-ID.localization-bundle.d.ts +0 -2
  60. package/esm/presentation/localization/bundles/id-ID.localization-bundle.d.ts.map +1 -1
  61. package/esm/presentation/localization/bundles/id-ID.localization-bundle.js +0 -2
  62. package/esm/presentation/localization/bundles/it-IT.localization-bundle.d.ts +0 -2
  63. package/esm/presentation/localization/bundles/it-IT.localization-bundle.d.ts.map +1 -1
  64. package/esm/presentation/localization/bundles/it-IT.localization-bundle.js +0 -2
  65. package/esm/presentation/localization/bundles/ja-JP.localization-bundle.d.ts +0 -2
  66. package/esm/presentation/localization/bundles/ja-JP.localization-bundle.d.ts.map +1 -1
  67. package/esm/presentation/localization/bundles/ja-JP.localization-bundle.js +0 -2
  68. package/esm/presentation/localization/bundles/ko-KR.localization-bundle.d.ts +0 -2
  69. package/esm/presentation/localization/bundles/ko-KR.localization-bundle.d.ts.map +1 -1
  70. package/esm/presentation/localization/bundles/ko-KR.localization-bundle.js +0 -2
  71. package/esm/presentation/localization/bundles/nl-NL.localization-bundle.d.ts +0 -2
  72. package/esm/presentation/localization/bundles/nl-NL.localization-bundle.d.ts.map +1 -1
  73. package/esm/presentation/localization/bundles/nl-NL.localization-bundle.js +0 -2
  74. package/esm/presentation/localization/bundles/pl-PL.localization-bundle.d.ts +0 -2
  75. package/esm/presentation/localization/bundles/pl-PL.localization-bundle.d.ts.map +1 -1
  76. package/esm/presentation/localization/bundles/pl-PL.localization-bundle.js +0 -2
  77. package/esm/presentation/localization/bundles/pt-BR.localization-bundle.d.ts +0 -2
  78. package/esm/presentation/localization/bundles/pt-BR.localization-bundle.d.ts.map +1 -1
  79. package/esm/presentation/localization/bundles/pt-BR.localization-bundle.js +0 -2
  80. package/esm/presentation/localization/bundles/pt-PT.localization-bundle.d.ts +0 -2
  81. package/esm/presentation/localization/bundles/pt-PT.localization-bundle.d.ts.map +1 -1
  82. package/esm/presentation/localization/bundles/pt-PT.localization-bundle.js +0 -2
  83. package/esm/presentation/localization/bundles/ru-RU.localization-bundle.d.ts +0 -2
  84. package/esm/presentation/localization/bundles/ru-RU.localization-bundle.d.ts.map +1 -1
  85. package/esm/presentation/localization/bundles/ru-RU.localization-bundle.js +0 -2
  86. package/esm/presentation/localization/bundles/sl-SI.localization-bundle.d.ts +0 -2
  87. package/esm/presentation/localization/bundles/sl-SI.localization-bundle.d.ts.map +1 -1
  88. package/esm/presentation/localization/bundles/sl-SI.localization-bundle.js +0 -2
  89. package/esm/presentation/localization/bundles/th-TH.localization-bundle.d.ts +0 -2
  90. package/esm/presentation/localization/bundles/th-TH.localization-bundle.d.ts.map +1 -1
  91. package/esm/presentation/localization/bundles/th-TH.localization-bundle.js +0 -2
  92. package/esm/presentation/localization/bundles/tr-TR.localization-bundle.d.ts +0 -2
  93. package/esm/presentation/localization/bundles/tr-TR.localization-bundle.d.ts.map +1 -1
  94. package/esm/presentation/localization/bundles/tr-TR.localization-bundle.js +0 -2
  95. package/esm/presentation/localization/bundles/uk-UA.localization-bundle.d.ts +0 -2
  96. package/esm/presentation/localization/bundles/uk-UA.localization-bundle.d.ts.map +1 -1
  97. package/esm/presentation/localization/bundles/uk-UA.localization-bundle.js +0 -2
  98. package/esm/presentation/localization/bundles/vi-VN.localization-bundle.d.ts +0 -2
  99. package/esm/presentation/localization/bundles/vi-VN.localization-bundle.d.ts.map +1 -1
  100. package/esm/presentation/localization/bundles/vi-VN.localization-bundle.js +0 -2
  101. package/esm/presentation/localization/bundles/zh-HK.localization-bundle.d.ts +0 -2
  102. package/esm/presentation/localization/bundles/zh-HK.localization-bundle.d.ts.map +1 -1
  103. package/esm/presentation/localization/bundles/zh-HK.localization-bundle.js +0 -2
  104. package/esm/presentation/localization/bundles/zh-Hans.localization-bundle.d.ts +0 -2
  105. package/esm/presentation/localization/bundles/zh-Hans.localization-bundle.d.ts.map +1 -1
  106. package/esm/presentation/localization/bundles/zh-Hans.localization-bundle.js +0 -2
  107. package/esm/presentation/localization/bundles/zh-Hant.localization-bundle.d.ts +0 -2
  108. package/esm/presentation/localization/bundles/zh-Hant.localization-bundle.d.ts.map +1 -1
  109. package/esm/presentation/localization/bundles/zh-Hant.localization-bundle.js +0 -2
  110. package/esm/sdk-ui-dashboard.d.ts +3 -0
  111. package/esm/types.d.ts +1 -1
  112. package/esm/types.js +1 -1
  113. package/package.json +26 -26
@@ -1 +1 @@
1
- {"version":3,"file":"stateInitializers.d.ts","sourceRoot":"","sources":["../../../../../src/model/commandHandlers/dashboard/common/stateInitializers.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEtD,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAG/C,OAAO,EAAE,KAAK,8BAA8B,EAAc,MAAM,2BAA2B,CAAC;AAC5F,OAAO,EAEH,KAAK,mCAAmC,EACxC,KAAK,UAAU,EACf,KAAK,yBAAyB,EAC9B,KAAK,+BAA+B,EAKpC,KAAK,sBAAsB,EAC3B,KAAK,iBAAiB,EAEtB,KAAK,wBAAwB,EAC7B,KAAK,QAAQ,EACb,KAAK,wBAAwB,EAC7B,KAAK,SAAS,EAGd,KAAK,MAAM,EAOd,MAAM,qBAAqB,CAAC;AAc7B,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,4CAA4C,CAAC;AAoB5E,OAAO,EACH,KAAK,gBAAgB,EAGxB,MAAM,+BAA+B,CAAC;AA+JvC,wBAAiB,+BAA+B,CAC5C,GAAG,EAAE,gBAAgB,EACrB,QAAQ,EAAE,SAAS,EACnB,gBAAgB,EAAE,iBAAiB,EACnC,YAAY,CAAC,EAAE,SAAS,CAAC,mCAAmC,CAAC,EAC7D,YAAY,CAAC,EAAE,MAAM,EACrB,mBAAmB,GAAE,wBAAwB,EAAO,GACrD,YAAY,CAAC;IACZ,WAAW,EAAE,KAAK,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC;IACvC,SAAS,EAAE,UAAU,GAAG,SAAS,CAAC;IAClC,QAAQ,EAAE,QAAQ,EAAE,CAAC;CACxB,CAAC,CA6GD;AAwJD,wBAAgB,YAAY,CACxB,GAAG,EAAE,gBAAgB,EACrB,WAAW,EAAE,MAAM,EAAE,GACtB,OAAO,CAAC,sBAAsB,EAAE,CAAC,CAInC;AAgGD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAiB,oCAAoC,CACjD,GAAG,EAAE,gBAAgB,EACrB,SAAS,EAAE,UAAU,EACrB,QAAQ,EAAE,QAAQ,EAAE,EACpB,QAAQ,EAAE,SAAS,EACnB,0CAA0C,EAAE,OAAO,EACnD,+BAA+B,EAAE,MAAM,CAAC,MAAM,EAAE,wBAAwB,GAAG,SAAS,CAAC,GAAG,SAAS,EAEjG,wBAAwB,EAAE,MAAM,CAAC,MAAM,EAAE,yBAAyB,EAAE,CAAC,GAAG,SAAS,EACjF,8BAA8B,EAAE,MAAM,CAAC,MAAM,EAAE,+BAA+B,EAAE,CAAC,EACjF,4BAA4B,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,EAC/D,0BAA0B,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,GAAG,WAAW,CAAC,EACrE,YAAY,CAAC,EAAE,SAAS,CAAC,mCAAmC,CAAC,EAC7D,kBAAkB,CAAC,EAAE,UAAU,EAC/B,wBAAwB,CAAC,EAAE,MAAM,EACjC,mBAAmB,GAAE,wBAAwB,EAAO,EACpD,0BAA0B,CAAC,EAAE,aAAa,CAAC,8BAA8B,CAAC,GAC3E,YAAY,CAAC,KAAK,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,CAqNzC"}
1
+ {"version":3,"file":"stateInitializers.d.ts","sourceRoot":"","sources":["../../../../../src/model/commandHandlers/dashboard/common/stateInitializers.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEtD,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAG/C,OAAO,EACH,KAAK,wBAAwB,EAC7B,KAAK,8BAA8B,EAEtC,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAEH,KAAK,mCAAmC,EACxC,KAAK,UAAU,EACf,KAAK,yBAAyB,EAC9B,KAAK,+BAA+B,EAKpC,KAAK,sBAAsB,EAC3B,KAAK,iBAAiB,EAEtB,KAAK,wBAAwB,EAC7B,KAAK,QAAQ,EACb,KAAK,wBAAwB,EAC7B,KAAK,SAAS,EAGd,KAAK,MAAM,EAOd,MAAM,qBAAqB,CAAC;AAW7B,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,4CAA4C,CAAC;AAoB5E,OAAO,EACH,KAAK,gBAAgB,EAGxB,MAAM,+BAA+B,CAAC;AAiKvC,wBAAiB,+BAA+B,CAC5C,GAAG,EAAE,gBAAgB,EACrB,QAAQ,EAAE,SAAS,EACnB,gBAAgB,EAAE,iBAAiB,EACnC,YAAY,CAAC,EAAE,SAAS,CAAC,mCAAmC,CAAC,EAC7D,YAAY,CAAC,EAAE,MAAM,EACrB,mBAAmB,GAAE,wBAAwB,EAAO,GACrD,YAAY,CAAC;IACZ,WAAW,EAAE,KAAK,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC;IACvC,SAAS,EAAE,UAAU,GAAG,SAAS,CAAC;IAClC,QAAQ,EAAE,QAAQ,EAAE,CAAC;CACxB,CAAC,CA6GD;AAwJD,wBAAgB,YAAY,CACxB,GAAG,EAAE,gBAAgB,EACrB,WAAW,EAAE,MAAM,EAAE,GACtB,OAAO,CAAC,sBAAsB,EAAE,CAAC,CAInC;AAgGD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,wBAAiB,oCAAoC,CACjD,GAAG,EAAE,gBAAgB,EACrB,SAAS,EAAE,UAAU,EACrB,QAAQ,EAAE,QAAQ,EAAE,EACpB,QAAQ,EAAE,SAAS,EACnB,0CAA0C,EAAE,OAAO,EACnD,+BAA+B,EAAE,MAAM,CAAC,MAAM,EAAE,wBAAwB,GAAG,SAAS,CAAC,GAAG,SAAS,EAEjG,wBAAwB,EAAE,MAAM,CAAC,MAAM,EAAE,yBAAyB,EAAE,CAAC,GAAG,SAAS,EACjF,8BAA8B,EAAE,MAAM,CAAC,MAAM,EAAE,+BAA+B,EAAE,CAAC,EACjF,4BAA4B,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,EAC/D,0BAA0B,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,GAAG,WAAW,CAAC,EACrE,YAAY,CAAC,EAAE,SAAS,CAAC,mCAAmC,CAAC,EAC7D,kBAAkB,CAAC,EAAE,UAAU,EAC/B,wBAAwB,CAAC,EAAE,MAAM,EACjC,mBAAmB,GAAE,wBAAwB,EAAO,EACpD,0BAA0B,CAAC,EAAE,aAAa,CAAC,8BAA8B,CAAC,EAC1E,wBAAwB,CAAC,EAAE,wBAAwB,EAAE,GACtD,YAAY,CAAC,KAAK,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,CA6NzC"}
@@ -1,10 +1,9 @@
1
1
  // (C) 2021-2026 GoodData Corporation
2
2
  import { cloneDeep, compact, isEmpty, update } from "lodash-es";
3
3
  import { call, select } from "redux-saga/effects";
4
- import { walkLayout } from "@gooddata/sdk-backend-spi";
4
+ import { walkLayout, } from "@gooddata/sdk-backend-spi";
5
5
  import { areObjRefsEqual, isDashboardAttributeFilter, isDashboardDateFilterWithDimension, isIdentifierRef, isInsightWidget, isObjRef, } from "@gooddata/sdk-model";
6
6
  import { dashboardFilterContextDefinition, dashboardFilterContextIdentity, } from "../../../../_staging/dashboard/dashboardFilterContext.js";
7
- import { mergeFilterContextFilters, } from "../../../../_staging/dashboard/dashboardFilterContextValidation.js";
8
7
  import { dashboardLayoutSanitize } from "../../../../_staging/dashboard/dashboardLayout.js";
9
8
  import { createDefaultFilterContext } from "../../../../_staging/dashboard/defaultFilterContext.js";
10
9
  import { DEFAULT_FISCAL_DATE_FILTER_PRESET } from "../../../../_staging/dateFilterConfig/defaultConfig.js";
@@ -26,6 +25,7 @@ import { resolveFilterDisplayForms } from "../../../utils/filterResolver.js";
26
25
  import { EmptyDashboardLayout, dashboardInitialize } from "./dashboardInitialize.js";
27
26
  import { loadAvailableDisplayFormRefs } from "./loadAvailableDisplayFormRefs.js";
28
27
  import { mergedMigratedAttributeFilters } from "./migratedAttributeFilters.js";
28
+ import { mergeDashboardOverrideFilters, resolveOverrideFiltersByTab } from "./overrideFiltersAcrossTabs.js";
29
29
  import { distributeParametersToTabs } from "./parameterHydration.js";
30
30
  /**
31
31
  * Processes a single tab's filterContext and returns initialized FilterContextState.
@@ -45,8 +45,9 @@ function* processExistingTabFilterContext(ctx, tab, effectiveDateFilterConfig, d
45
45
  // Extract filter context definition or create a default filter context
46
46
  const originalSanitizedFilterContextDefinition = dashboardFilterContextDefinition(tabAsDashboard, effectiveDateFilterConfig);
47
47
  const filterContextIdentity = dashboardFilterContextIdentity(tabAsDashboard);
48
- // Merge with override filters if provided
49
- const { mergedFilters, validationResults } = mergeFilterContextFilters(originalSanitizedFilterContextDefinition.filters, overrideDefaultFilters ?? [], {
48
+ // Merge with override filters if provided. A common date of all time is the absence of the
49
+ // filter, so the merge also writes a common date override that has nothing to match.
50
+ const { mergedFilters, validationResults } = mergeDashboardOverrideFilters(originalSanitizedFilterContextDefinition.filters, overrideDefaultFilters ?? [], {
50
51
  dateFilterConfig: tab.dateFilterConfig,
51
52
  dateFilterConfigs: tab.dateFilterConfigs,
52
53
  attributeFilterConfigs: tab.attributeFilterConfigs,
@@ -395,8 +396,10 @@ function getDisplayAsLabels(attributeFilterConfigs) {
395
396
  * @param displayForms - specify display forms that should be used for in-memory resolution of
396
397
  * attribute filter display forms to metadata objects
397
398
  * @param persistedDashboard - dashboard to use for the persisted dashboard state slice in case it needs to be different from the dashboard param
399
+ * @param attributesWithReferences - attributes of the attribute filters, used to match an override filter
400
+ * to the same filter on another tab when filters persist across tabs
398
401
  */
399
- export function* actionsToInitializeExistingDashboard(ctx, dashboard, insights, settings, isImmediateAttributeFilterMigrationEnabled, originalFilterContextDefinition, migratedAttributeFilters, migratedAttributeFilterConfigs, effectiveDateFilterConfigMap, tabsDateFilterConfigSource, displayForms, persistedDashboard, activeTabLocalIdentifier, workspaceParameters = [], unavailableObjectsOverride) {
402
+ export function* actionsToInitializeExistingDashboard(ctx, dashboard, insights, settings, isImmediateAttributeFilterMigrationEnabled, originalFilterContextDefinition, migratedAttributeFilters, migratedAttributeFilterConfigs, effectiveDateFilterConfigMap, tabsDateFilterConfigSource, displayForms, persistedDashboard, activeTabLocalIdentifier, workspaceParameters = [], unavailableObjectsOverride, attributesWithReferences) {
400
403
  const effectiveActiveTabId = activeTabLocalIdentifier ?? dashboard.tabs?.[0]?.localIdentifier ?? DEFAULT_TAB_ID;
401
404
  const effectiveProps = getEffectiveDashboardProperties(dashboard, effectiveActiveTabId);
402
405
  const sanitizedDashboard = updateDashboard({
@@ -425,12 +428,13 @@ export function* actionsToInitializeExistingDashboard(ctx, dashboard, insights,
425
428
  if (customizedDashboard?.tabs && customizedDashboard.tabs.length > 0) {
426
429
  // Process each tab to build complete TabState with filterContext
427
430
  const processedTabs = [];
431
+ const persistFiltersAcrossTabs = (settings.enableDashboardPersistentFiltersAcrossTabs ?? false) &&
432
+ dashboard.enablePersistentFiltersAcrossTabs === true;
433
+ // The tab the link opens on keeps the override filters as copied. When filters persist
434
+ // across tabs, every other tab receives those values on its own filters.
435
+ const overridesByTab = resolveOverrideFiltersByTab(customizedDashboard.tabs, ctx.config?.overrideDefaultFilters, effectiveActiveTabId, persistFiltersAcrossTabs, attributesWithReferences);
428
436
  for (const tab of customizedDashboard.tabs) {
429
- const isActiveTab = tab.localIdentifier === effectiveActiveTabId;
430
- // Override default filters are only applied to the active tab
431
- const overrideDefaultFilters = isActiveTab && ctx.config?.overrideDefaultFilters
432
- ? ctx.config?.overrideDefaultFilters
433
- : undefined;
437
+ const overrideDefaultFilters = overridesByTab[tab.localIdentifier];
434
438
  // Process this tab's filterContext
435
439
  const [tabFilterContext, tabValidationResults] = yield call(processExistingTabFilterContext, ctx, tab, effectiveDateFilterConfigMap[tab.localIdentifier], dashboard.dataSets, overrideDefaultFilters, isImmediateAttributeFilterMigrationEnabled, migratedAttributeFilters?.[tab.localIdentifier] ?? [], originalFilterContextDefinition?.[tab.localIdentifier], displayForms, dashboard, unavailableObjectsOverride);
436
440
  validationResults.push(...(tabValidationResults ?? []));
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/model/commandHandlers/dashboard/initializeDashboardHandler/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,WAAW,EAAgB,MAAM,uBAAuB,CAAC;AACvE,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAG/C,OAAO,EACH,KAAK,wBAAwB,EAIhC,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACH,KAAK,UAAU,EAKf,KAAK,sBAAsB,EAK3B,KAAK,MAAM,EAOd,MAAM,qBAAqB,CAAC;AAQ7B,OAAO,EAAE,KAAK,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AA0B1E,OAAO,EACH,KAAK,gBAAgB,EAGxB,MAAM,+BAA+B,CAAC;AA+JvC,KAAK,0BAA0B,GAAG;IAC9B,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,wBAAwB,EAAE,wBAAwB,EAAE,CAAC;CACxD,CAAC;AAuYF,wBAAiB,cAAc,CAAC,GAAG,EAAE,gBAAgB,EAAE,GAAG,EAAE,mBAAmB;;;uIAyB9E;AAgED;;;;GAIG;AACH,wBAAiB,2BAA2B,CACxC,GAAG,EAAE,gBAAgB,EACrB,SAAS,EAAE,UAAU,EACrB,SAAS,CAAC,EAAE,0BAA0B;;;0IAiBzC;AAED,wBAAiB,qBAAqB,CAAC,GAAG,EAAE,gBAAgB,sNAW3D;AAqCD,wBAAiB,0BAA0B,CAAC,GAAG,EAAE,gBAAgB,EAAE,GAAG,EAAE,mBAAmB,GAAG,YAAY,CA0CzG"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/model/commandHandlers/dashboard/initializeDashboardHandler/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,WAAW,EAAgB,MAAM,uBAAuB,CAAC;AACvE,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAG/C,OAAO,EACH,KAAK,wBAAwB,EAIhC,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACH,KAAK,UAAU,EAKf,KAAK,sBAAsB,EAK3B,KAAK,MAAM,EAOd,MAAM,qBAAqB,CAAC;AAQ7B,OAAO,EAAE,KAAK,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AA0B1E,OAAO,EACH,KAAK,gBAAgB,EAGxB,MAAM,+BAA+B,CAAC;AA+JvC,KAAK,0BAA0B,GAAG;IAC9B,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,wBAAwB,EAAE,wBAAwB,EAAE,CAAC;CACxD,CAAC;AAyYF,wBAAiB,cAAc,CAAC,GAAG,EAAE,gBAAgB,EAAE,GAAG,EAAE,mBAAmB;;;uIAyB9E;AAuED;;;;GAIG;AACH,wBAAiB,2BAA2B,CACxC,GAAG,EAAE,gBAAgB,EACrB,SAAS,EAAE,UAAU,EACrB,SAAS,CAAC,EAAE,0BAA0B;;;0IAiBzC;AAED,wBAAiB,qBAAqB,CAAC,GAAG,EAAE,gBAAgB,sNAW3D;AAqCD,wBAAiB,0BAA0B,CAAC,GAAG,EAAE,gBAAgB,EAAE,GAAG,EAAE,mBAAmB,GAAG,YAAY,CA0CzG"}
@@ -213,7 +213,7 @@ function* loadExistingDashboard(ctx, cmd, dashboardRef) {
213
213
  const workspaceParametersList = Array.isArray(workspaceParameters) ? workspaceParameters : [];
214
214
  const initActions = yield call(actionsToInitializeExistingDashboard, ctx, dashboard, insights, config.settings, config.settings.enableImmediateAttributeFilterDisplayAsLabelMigration ?? false, undefined, undefined, tabsAttributeFilterConfigs, tabsDateFilterConfig, tabsDateFilterConfigSource, createDisplayFormMap([], []),
215
215
  // the default filter view changes only the working filters, never the persisted ones
216
- cmd.payload.persistedDashboard ?? loadedDashboard, resolvedActiveTabId, workspaceParametersList);
216
+ cmd.payload.persistedDashboard ?? loadedDashboard, resolvedActiveTabId, workspaceParametersList, undefined, preloadedAttributeFilters?.attributesWithReferences);
217
217
  const catalogPayload = {
218
218
  dateHierarchyTemplates,
219
219
  };
@@ -377,12 +377,16 @@ function makeCatalogParametersPayload(result) {
377
377
  return { status: "loaded", parameters: result };
378
378
  }
379
379
  /**
380
- * The attributes of the attribute filters, which match the filters of the tabs when the default view of the
381
- * active tab is written to the other tabs. The view is not shared, or the attributes fail to load: none,
382
- * so filters match on equal display form refs.
380
+ * The attributes of the attribute filters, which match the filters of the tabs when a selection is
381
+ * written to the other tabs: the default view of the active tab, or embed-url filter overrides.
382
+ * Nothing is shared, or the attributes fail to load: none, so filters match on equal display form refs.
383
383
  */
384
384
  function* loadAttributesForSharedDefaultFilterView(ctx, dashboard, filterViews, renderMode, options, unavailableObjects) {
385
- if (!isDefaultFilterViewSharedAcrossTabs(dashboard, filterViews, renderMode, options)) {
385
+ const shareOverrideFilters = !!options.persistFiltersAcrossTabs &&
386
+ (dashboard.tabs?.length ?? 0) > 1 &&
387
+ (ctx.config?.overrideDefaultFilters?.length ?? 0) > 0;
388
+ if (!shareOverrideFilters &&
389
+ !isDefaultFilterViewSharedAcrossTabs(dashboard, filterViews, renderMode, options)) {
386
390
  return undefined;
387
391
  }
388
392
  const refs = attributeFilterDisplayFormRefs(dashboard, unavailableObjects);
@@ -142,7 +142,7 @@ function* resetDashboardFromPersisted(ctx, renderMode) {
142
142
  const displayForms = yield select(selectAllCatalogDisplayFormsMap);
143
143
  const resolvedInsightsValues = [...resolvedInsights.resolved.values()];
144
144
  const workspaceParameters = yield select(selectCatalogParameters);
145
- const initActions = yield call(actionsToInitializeExistingDashboard, ctx, dashboardWithUpdatedFilterContext, resolvedInsightsValues, settings, isImmediateAttributeFilterMigrationEnabled, effectiveOriginalFilterContext, migratedAttributeFilters, effectiveAttributeFilterConfigs, dateFilterConfig, tabsDateFilterConfigSource, displayForms, persistedDashboard, effectiveActiveTabId, workspaceParameters);
145
+ const initActions = yield call(actionsToInitializeExistingDashboard, ctx, dashboardWithUpdatedFilterContext, resolvedInsightsValues, settings, isImmediateAttributeFilterMigrationEnabled, effectiveOriginalFilterContext, migratedAttributeFilters, effectiveAttributeFilterConfigs, dateFilterConfig, tabsDateFilterConfigSource, displayForms, persistedDashboard, effectiveActiveTabId, workspaceParameters, undefined, attributesWithReferences);
146
146
  batch = [
147
147
  ...initActions,
148
148
  filterViewsActions.setDefaultFilterViewAppliedTabs(effectiveActiveTabId ? [effectiveActiveTabId] : []),
@@ -81,8 +81,8 @@ function intersectAttributeFilters(dashFilter, sourceFilter) {
81
81
  * |---------------|---------------|-------------------------------------------|
82
82
  * | Positive (A) | Positive (B) | Positive (A ∩ B) |
83
83
  * | Negative (A) | Negative (B) | Negative (A ∪ B) |
84
- * | Positive (A) | Negative (B) | Positive (A \ B) |
85
- * | Negative (A) | Positive (B) | Positive (B \ A) |
84
+ * | Positive (A) | Negative (B) | Positive (A ∖ B) |
85
+ * | Negative (A) | Positive (B) | Positive (B ∖ A) |
86
86
  */
87
87
  function intersectElements(aValues, aNegative, bValues, bNegative) {
88
88
  if (!aNegative && !bNegative) {
@@ -1 +1 @@
1
- {"version":3,"file":"tabSyncRules.d.ts","sourceRoot":"","sources":["../../../../../src/model/commandHandlers/filterContext/tabSync/tabSyncRules.ts"],"names":[],"mappings":"AAqCA,OAAO,EAA4B,KAAK,kBAAkB,EAAoB,MAAM,mBAAmB,CAAC;AAExG,KAAK,cAAc,GAAG,kBAAkB,CAAC,GAAG,CAAC,CAAC;AAye9C;;;;;GAKG;AACH,eAAO,MAAM,YAAY,EAAE,WAAW,CAAC,MAAM,EAAE,cAAc,CAG3D,CAAC"}
1
+ {"version":3,"file":"tabSyncRules.d.ts","sourceRoot":"","sources":["../../../../../src/model/commandHandlers/filterContext/tabSync/tabSyncRules.ts"],"names":[],"mappings":"AAsCA,OAAO,EAA4B,KAAK,kBAAkB,EAAoB,MAAM,mBAAmB,CAAC;AAExG,KAAK,cAAc,GAAG,kBAAkB,CAAC,GAAG,CAAC,CAAC;AAwlB9C;;;;;GAKG;AACH,eAAO,MAAM,YAAY,EAAE,WAAW,CAAC,MAAM,EAAE,cAAc,CAG3D,CAAC"}
@@ -2,6 +2,7 @@
2
2
  import { areObjRefsEqual, dashboardAttributeFilterItemLocalIdentifier, dashboardFilterLocalIdentifier, isAllTimeDashboardDateFilter, isDashboardAttributeFilter, isDashboardAttributeFilterItem, isDashboardCommonDateFilter, isDashboardDateFilter, isDashboardDateFilterWithDimension, isDashboardMeasureValueFilter, isNoopAllTimeDashboardDateFilter, } from "@gooddata/sdk-model";
3
3
  import { applyMirroredFilterValue, findAppliedFilterForStaged, findCounterpartFilter, findOriginalFilter, isCrossFilteringVirtualFilter, retargetAttributeFilterItem, targetAcceptsAttributeFilterValue, } from "../../../store/tabs/filterContext/filterSync.js";
4
4
  import { tabsActions } from "../../../store/tabs/index.js";
5
+ import { isDisplayFormMetadataReferencedBy } from "../../../utils/attributeFilterMatching.js";
5
6
  function defineRule(actionCreator, rule) {
6
7
  return defineActionsRule(actionCreator, (payload, target, ctx) => {
7
8
  const targetPayload = rule(payload, target, ctx);
@@ -91,6 +92,35 @@ function mirroredListSelection(ctx, target, sourceLocalId, restoreTargetOriginal
91
92
  ? counterpart
92
93
  : undefined;
93
94
  }
95
+ function hasDisplayForm(counterpart, displayForm) {
96
+ return areObjRefsEqual(counterpart.attributeFilter.displayForm, displayForm);
97
+ }
98
+ /**
99
+ * Actions that let `counterpart` take `displayForm` and keep showing the label it shows now.
100
+ * The target tab learns the metadata of `displayForm`, and a counterpart without a display-as label
101
+ * gets its current display form as one. The display form itself is changed by the caller.
102
+ */
103
+ function prepareDisplayFormChange(ctx, targetTabState, targetFilter, sourceDisplayForm) {
104
+ const actions = [];
105
+ const targetDisplayForms = targetTabState.filterContext?.attributeFilterDisplayForms;
106
+ const metadata = (ctx.source.filterContext?.attributeFilterDisplayForms ?? []).find((candidate) => isDisplayFormMetadataReferencedBy(candidate, sourceDisplayForm));
107
+ if (metadata &&
108
+ targetDisplayForms &&
109
+ !targetDisplayForms.some((candidate) => isDisplayFormMetadataReferencedBy(candidate, sourceDisplayForm))) {
110
+ actions.push(tabsActions.addAttributeFilterDisplayForm({
111
+ displayForm: metadata,
112
+ }));
113
+ }
114
+ const localIdentifier = targetFilter.attributeFilter.localIdentifier;
115
+ const hasDisplayAsLabel = targetTabState.attributeFilterConfigs?.attributeFilterConfigs?.some((config) => config.localIdentifier === localIdentifier && config.displayAsLabel);
116
+ if (!hasDisplayAsLabel) {
117
+ actions.push(tabsActions.changeDisplayAsLabel({
118
+ localIdentifier,
119
+ displayAsLabel: targetFilter.attributeFilter.displayForm,
120
+ }));
121
+ }
122
+ return actions;
123
+ }
94
124
  function findMeasureValueCounterpart(ctx, target, sourceLocalId) {
95
125
  const sourceFilter = findFilterByLocalId(ctx.source, sourceLocalId);
96
126
  if (!isDashboardMeasureValueFilter(sourceFilter)) {
@@ -112,14 +142,23 @@ function toUpsertDateFilterPayload(filter) {
112
142
  if (isAllTimeDashboardDateFilter(filter)) {
113
143
  return { type: "allTime", ...shared };
114
144
  }
115
- return { type, granularity, from, to, ...(boundedFilter ? { boundedFilter } : {}), ...shared };
145
+ return {
146
+ type,
147
+ granularity,
148
+ from,
149
+ to,
150
+ ...(boundedFilter ? { boundedFilter } : {}),
151
+ ...shared,
152
+ };
116
153
  }
117
154
  /**
118
155
  * Saved date filter of `target`. A common date filter without a saved original is all time, which is
119
156
  * stored as the absence of the filter. A dimension date filter without a saved original is left unchanged.
120
157
  */
121
158
  function savedDateFilterPayload(target, applied, dataSet) {
122
- const original = findOriginalFilter(target, applied ?? { dateFilter: { type: "relative", granularity: "GDC.time.date" } });
159
+ const original = findOriginalFilter(target, applied ?? {
160
+ dateFilter: { type: "relative", granularity: "GDC.time.date" },
161
+ });
123
162
  if (isDashboardDateFilter(original)) {
124
163
  return toUpsertDateFilterPayload(original);
125
164
  }
@@ -168,7 +207,9 @@ const filterContextRules = [
168
207
  if (!target.filterContext?.attributeFilterDisplayForms) {
169
208
  return undefined;
170
209
  }
171
- return { displayForm: "displayForm" in payload ? payload.displayForm : payload };
210
+ return {
211
+ displayForm: "displayForm" in payload ? payload.displayForm : payload,
212
+ };
172
213
  }),
173
214
  // Selection changes swap the display form together with elements expressed in it, so the swap
174
215
  // follows the selection. Filter configuration handlers do not sync these actions.
@@ -191,7 +232,10 @@ const filterContextRules = [
191
232
  }
192
233
  const filterLocalId = dashboardFilterLocalIdentifier(counterpart);
193
234
  if (!payload.restoreTargetOriginal) {
194
- const changeDisplayForm = tabsActions.changeAttributeDisplayForm({ ...payload, filterLocalId });
235
+ const changeDisplayForm = tabsActions.changeAttributeDisplayForm({
236
+ ...payload,
237
+ filterLocalId,
238
+ });
195
239
  const currentDisplayForm = counterpart.attributeFilter.displayForm;
196
240
  const hasDisplayAsLabel = target.attributeFilterConfigs?.attributeFilterConfigs?.some((config) => config.localIdentifier === filterLocalId && config.displayAsLabel);
197
241
  if (hasDisplayAsLabel || areObjRefsEqual(currentDisplayForm, payload.displayForm)) {
@@ -241,31 +285,51 @@ const filterContextRules = [
241
285
  ];
242
286
  // Staged edits stay on their tab until applied. With `restoreTargetOriginal`, every tab restores its own saved value.
243
287
  const selectionRules = [
244
- defineRule(tabsActions.updateAttributeFilterSelection, (payload, target, ctx) => {
288
+ // Elements are values of the display form of their filter, so the counterpart takes the display
289
+ // form of the written elements.
290
+ defineActionsRule(tabsActions.updateAttributeFilterSelection, (payload, target, ctx) => {
245
291
  // Every tab migrates its own filters, so a migrated selection stays on its tab.
246
292
  if (payload.isWorkingSelectionChange || payload.isResultOfMigration) {
247
- return undefined;
293
+ return [];
248
294
  }
249
295
  const counterpart = mirroredListSelection(ctx, target, payload.filterLocalId, payload.restoreTargetOriginal);
250
296
  if (!counterpart) {
251
- return undefined;
297
+ return [];
252
298
  }
253
- const original = payload.restoreTargetOriginal ? findOriginalFilter(target, counterpart) : undefined;
254
- if (payload.restoreTargetOriginal && !isDashboardAttributeFilter(original)) {
255
- return undefined;
299
+ const filterLocalId = counterpart.attributeFilter.localIdentifier;
300
+ const filter = payload.restoreTargetOriginal
301
+ ? findOriginalFilter(target, counterpart)
302
+ : findFilterByLocalId(ctx.source, payload.filterLocalId);
303
+ if (!isDashboardAttributeFilter(filter)) {
304
+ return [];
256
305
  }
257
- return {
306
+ const updateSelection = tabsActions.updateAttributeFilterSelection({
258
307
  ...payload,
259
- filterLocalId: counterpart.attributeFilter.localIdentifier,
260
- ...(isDashboardAttributeFilter(original)
308
+ filterLocalId,
309
+ ...(payload.restoreTargetOriginal
261
310
  ? {
262
- elements: original.attributeFilter.attributeElements,
263
- negativeSelection: original.attributeFilter.negativeSelection,
311
+ elements: filter.attributeFilter.attributeElements,
312
+ negativeSelection: filter.attributeFilter.negativeSelection,
264
313
  }
265
314
  : {}),
266
315
  // Every tab migrates its own filters.
267
316
  enableImmediateAttributeFilterDisplayAsLabelMigration: false,
268
- };
317
+ });
318
+ const displayForm = filter.attributeFilter.displayForm;
319
+ if (hasDisplayForm(counterpart, displayForm)) {
320
+ return [updateSelection];
321
+ }
322
+ return [
323
+ // A restored filter takes back its own saved display form, which its tab already knows.
324
+ ...(payload.restoreTargetOriginal
325
+ ? []
326
+ : prepareDisplayFormChange(ctx, target, counterpart, displayForm)),
327
+ tabsActions.changeAttributeDisplayForm({
328
+ filterLocalId,
329
+ displayForm,
330
+ }),
331
+ updateSelection,
332
+ ];
269
333
  }),
270
334
  defineRule(tabsActions.replaceAttributeFilterItem, (payload, target, ctx) => {
271
335
  if (payload.isWorkingSelectionChange) {
@@ -292,7 +356,11 @@ const selectionRules = [
292
356
  !targetAcceptsAttributeFilterValue(target, counterpart, replacement)) {
293
357
  return undefined;
294
358
  }
295
- return { ...payload, filterLocalId, filter: retargetAttributeFilterItem(replacement, filterLocalId) };
359
+ return {
360
+ ...payload,
361
+ filterLocalId,
362
+ filter: retargetAttributeFilterItem(replacement, filterLocalId),
363
+ };
296
364
  }),
297
365
  defineRule(tabsActions.clearAttributeFiltersSelection, (payload, target, ctx) => {
298
366
  const filterLocalIds = payload.filterLocalIds.flatMap((filterLocalId) => {
@@ -302,7 +370,10 @@ const selectionRules = [
302
370
  if (filterLocalIds.length === 0) {
303
371
  return undefined;
304
372
  }
305
- return { filterLocalIds, ...(payload.restoreTargetOriginal ? { restoreOriginal: true } : {}) };
373
+ return {
374
+ filterLocalIds,
375
+ ...(payload.restoreTargetOriginal ? { restoreOriginal: true } : {}),
376
+ };
306
377
  }),
307
378
  defineRule(tabsActions.upsertDateFilter, (payload, target) => {
308
379
  if (payload.isWorkingSelectionChange || !target.filterContext?.filterContextDefinition) {
@@ -321,7 +392,10 @@ const selectionRules = [
321
392
  }
322
393
  // A common date filter created on the target does not take the local identifier of the source.
323
394
  const ownValue = payload.restoreTargetOriginal ? value.localIdentifier : undefined;
324
- return { ...value, localIdentifier: counterpart?.dateFilter.localIdentifier ?? ownValue };
395
+ return {
396
+ ...value,
397
+ localIdentifier: counterpart?.dateFilter.localIdentifier ?? ownValue,
398
+ };
325
399
  }),
326
400
  defineRule(tabsActions.changeMeasureValueFilterCondition, (payload, target, ctx) => {
327
401
  if (payload.isWorkingSelectionChange) {
@@ -337,7 +411,11 @@ const selectionRules = [
337
411
  }
338
412
  const original = findOriginalFilter(target, counterpart);
339
413
  return isDashboardMeasureValueFilter(original)
340
- ? { ...payload, localIdentifier, conditions: original.dashboardMeasureValueFilter.conditions }
414
+ ? {
415
+ ...payload,
416
+ localIdentifier,
417
+ conditions: original.dashboardMeasureValueFilter.conditions,
418
+ }
341
419
  : undefined;
342
420
  }),
343
421
  defineRule(tabsActions.setMeasureValueFilterDimensionality, (payload, target, ctx) => {
@@ -363,13 +441,26 @@ const selectionRules = [
363
441
  return values.length > 0 ? { ...payload, values } : undefined;
364
442
  }),
365
443
  // Other tabs receive the committed values of the source tab, not their own staged values.
366
- defineRule(tabsActions.applyWorkingSelection, (_payload, target, ctx) => {
444
+ // A committed list filter brings its display form, which the mirrored selection writes.
445
+ defineActionsRule(tabsActions.applyWorkingSelection, (_payload, target, ctx) => {
367
446
  const filters = committedFilterValues(ctx, target);
368
447
  const parameters = committedParameterValues(ctx, target);
369
448
  if (filters.length === 0 && parameters.length === 0) {
370
- return undefined;
449
+ return [];
371
450
  }
372
- return { mirroredSelection: { filters, parameters } };
451
+ const displayFormChanges = filters.filter(isDashboardAttributeFilter).flatMap((filter) => {
452
+ const targetFilter = findFilterByLocalId(target, filter.attributeFilter.localIdentifier);
453
+ return isDashboardAttributeFilter(targetFilter) &&
454
+ !hasDisplayForm(targetFilter, filter.attributeFilter.displayForm)
455
+ ? prepareDisplayFormChange(ctx, target, targetFilter, filter.attributeFilter.displayForm)
456
+ : [];
457
+ });
458
+ return [
459
+ ...displayFormChanges,
460
+ tabsActions.applyWorkingSelection({
461
+ mirroredSelection: { filters, parameters },
462
+ }),
463
+ ];
373
464
  }),
374
465
  ];
375
466
  /**
@@ -5,7 +5,7 @@ interface IParameterDependenciesLoadResult {
5
5
  failedRoots: IdentifierRef[];
6
6
  }
7
7
  /**
8
- * Loads the root -> parameter dependencies of `roots` from the workspace references service.
8
+ * Loads the root -\> parameter dependencies of `roots` from the workspace references service.
9
9
  *
10
10
  * @remarks
11
11
  * Walks the dependency graph in `direction: "down"` from each root, then collects the parameter
@@ -2,7 +2,7 @@
2
2
  import { isUnexpectedResponseError } from "@gooddata/sdk-backend-spi";
3
3
  import { insightRef, isIdentifierRef, serializeObjRef, } from "@gooddata/sdk-model";
4
4
  /**
5
- * Loads the root -> parameter dependencies of `roots` from the workspace references service.
5
+ * Loads the root -\> parameter dependencies of `roots` from the workspace references service.
6
6
  *
7
7
  * @remarks
8
8
  * Walks the dependency graph in `direction: "down"` from each root, then collects the parameter
@@ -1 +1 @@
1
- {"version":3,"file":"createDashboardTabHandler.d.ts","sourceRoot":"","sources":["../../../../src/model/commandHandlers/tabs/createDashboardTabHandler.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAmB/C,OAAO,EAAE,KAAK,mBAAmB,EAAsB,MAAM,wBAAwB,CAAC;AAgBtF,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAuEnE;;GAEG;AACH,wBAAiB,yBAAyB,CAAC,GAAG,EAAE,gBAAgB,EAAE,GAAG,EAAE,mBAAmB,GAAG,YAAY,CAyFxG"}
1
+ {"version":3,"file":"createDashboardTabHandler.d.ts","sourceRoot":"","sources":["../../../../src/model/commandHandlers/tabs/createDashboardTabHandler.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAgB/C,OAAO,EAAE,KAAK,mBAAmB,EAAsB,MAAM,wBAAwB,CAAC;AAatF,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAyDnE;;GAEG;AACH,wBAAiB,yBAAyB,CAAC,GAAG,EAAE,gBAAgB,EAAE,GAAG,EAAE,mBAAmB,GAAG,YAAY,CAuExG"}
@@ -1,5 +1,4 @@
1
1
  // (C) 2025-2026 GoodData Corporation
2
- import { cloneDeep } from "lodash-es";
3
2
  import { call, put, select } from "redux-saga/effects";
4
3
  import { createDefaultFilterContext } from "../../../_staging/dashboard/defaultFilterContext.js";
5
4
  import { DEFAULT_FISCAL_DATE_FILTER_PRESET } from "../../../_staging/dateFilterConfig/defaultConfig.js";
@@ -10,16 +9,13 @@ import { dashboardTabCreated } from "../../events/tabs.js";
10
9
  import { dispatchDashboardEvent } from "../../store/_infra/eventDispatcher.js";
11
10
  import { InitialUndoState } from "../../store/_infra/undoEnhancer.js";
12
11
  import { selectActiveCalendars, selectDateFilterConfig, selectSettings, } from "../../store/config/configSelectors.js";
13
- import { selectCrossFilteringFiltersLocalIdentifiersByTab } from "../../store/drill/drillSelectors.js";
14
- import { selectEnablePersistentFiltersAcrossTabs } from "../../store/meta/metaSelectors.js";
15
- import { seedSyncedTabFilters } from "../../store/tabs/filterContext/filterSync.js";
16
12
  import { tabsActions } from "../../store/tabs/index.js";
17
13
  import { selectScreen } from "../../store/tabs/layout/layoutSelectors.js";
18
14
  import { selectActiveTabLocalIdentifier, selectTabs } from "../../store/tabs/tabsSelectors.js";
19
15
  import { generateTabLocalIdentifier } from "../../utils/tabLocalIdentifier.js";
20
16
  import { EmptyDashboardLayout } from "../dashboard/common/dashboardInitialize.js";
21
17
  import { switchDashboardTabHandler } from "./switchDashboardTabHandler.js";
22
- const getTabState = ({ title, localIdentifier, isRenaming, filterContext, originalFilterContext, attributeFilterDisplayForms, dateFilterConfig, dateFilterConfigs, attributeFilterConfigs, measureValueFilterConfigs, filterGroupsConfig, layout, screen, }) => {
18
+ const getTabState = ({ title, localIdentifier, isRenaming, filterContext, dateFilterConfig, dateFilterConfigs, attributeFilterConfigs, layout, screen, }) => {
23
19
  return {
24
20
  title,
25
21
  localIdentifier,
@@ -27,8 +23,6 @@ const getTabState = ({ title, localIdentifier, isRenaming, filterContext, origin
27
23
  filterContext: {
28
24
  filtersWithInvalidSelection: [],
29
25
  filterContextDefinition: filterContext,
30
- originalFilterContextDefinition: originalFilterContext,
31
- attributeFilterDisplayForms,
32
26
  },
33
27
  dateFilterConfig: {
34
28
  dateFilterConfig: undefined,
@@ -42,10 +36,6 @@ const getTabState = ({ title, localIdentifier, isRenaming, filterContext, origin
42
36
  attributeFilterConfigs: {
43
37
  attributeFilterConfigs,
44
38
  },
45
- measureValueFilterConfigs: {
46
- measureValueFilterConfigs,
47
- },
48
- filterGroupsConfig,
49
39
  layout: {
50
40
  layout: layout,
51
41
  stash: {},
@@ -68,7 +58,7 @@ export function* createDashboardTabHandler(ctx, cmd) {
68
58
  const activeCalendars = yield select(selectActiveCalendars);
69
59
  const screen = yield select(selectScreen);
70
60
  const updatedTabs = (tabs ?? []).slice();
71
- // 2. Create new tab with an empty layout and a default filter context (seeded from the active tab when filters sync across tabs)
61
+ // 2. Create new tab with an empty filter context and layout
72
62
  const effectiveDateFilterConfig = activeCalendars?.fiscal &&
73
63
  activeCalendars?.default === "FISCAL" &&
74
64
  configHasFiscalPresets(dateFilterConfig)
@@ -76,27 +66,13 @@ export function* createDashboardTabHandler(ctx, cmd) {
76
66
  : dateFilterConfig;
77
67
  const newTabId = generateTabLocalIdentifier();
78
68
  const newTabFilterContext = createDefaultFilterContext(effectiveDateFilterConfig, true);
79
- // Synced writes only update existing counterparts and reset needs originals to restore to,
80
- // so a tab created while sync is on must start with the synced filters as its saved state.
81
- const activeTab = tabs?.find((tab) => tab.localIdentifier === activeTabLocalIdentifier);
82
- const crossFilteringLocalIdsByTab = yield select(selectCrossFilteringFiltersLocalIdentifiersByTab);
83
- const enablePersistentFiltersAcrossTabs = yield select(selectEnablePersistentFiltersAcrossTabs);
84
- const seed = enablePersistentFiltersAcrossTabs && activeTab
85
- ? seedSyncedTabFilters(activeTab, newTabFilterContext, crossFilteringLocalIdsByTab)
86
- : undefined;
87
69
  const newTab = getTabState({
88
70
  localIdentifier: newTabId,
89
71
  title,
90
72
  layout: EmptyDashboardLayout,
91
73
  screen,
92
- filterContext: seed?.filterContextDefinition ?? newTabFilterContext,
93
- originalFilterContext: seed ? cloneDeep(seed.filterContextDefinition) : undefined,
94
- attributeFilterDisplayForms: seed?.attributeFilterDisplayForms,
74
+ filterContext: newTabFilterContext,
95
75
  dateFilterConfig,
96
- dateFilterConfigs: seed?.dateFilterConfigs,
97
- attributeFilterConfigs: seed?.attributeFilterConfigs,
98
- measureValueFilterConfigs: seed?.measureValueFilterConfigs,
99
- filterGroupsConfig: seed?.filterGroupsConfig,
100
76
  isRenaming: shouldStartRenaming,
101
77
  });
102
78
  // 4. Insert new tab at specified index (or append)
@@ -1,5 +1,5 @@
1
1
  import { type IAttributeWithReferences } from "@gooddata/sdk-backend-spi";
2
- import { type DashboardAttributeFilterItem, type FilterContextItem, type IAttributeDisplayFormMetadataObject, type IDashboardAttributeFilterConfig, type IDashboardDateFilterConfigItem, type IDashboardFilterGroupsConfig, type IDashboardMeasureValueFilterConfig, type IFilterContextDefinition, type ObjRef, type ParameterValue } from "@gooddata/sdk-model";
2
+ import { type DashboardAttributeFilterItem, type FilterContextItem, type ObjRef, type ParameterValue } from "@gooddata/sdk-model";
3
3
  import { type ITabState } from "../tabsState.js";
4
4
  import { type WorkingFilterContextItem } from "./filterContextState.js";
5
5
  type StagedFilter = FilterContextItem | WorkingFilterContextItem;
@@ -63,6 +63,7 @@ export declare function preserveFilterDependencies(existing: DashboardAttributeF
63
63
  /**
64
64
  * Copies an applied source filter onto an existing target filter, keeping the target's
65
65
  * local identifier, parent dependencies, and measure-value dimensionality. Does not create a filter.
66
+ * A list filter takes the display form of the source, because its elements are values of that display form.
66
67
  *
67
68
  * @internal
68
69
  */
@@ -99,27 +100,6 @@ export declare function writeMirroredSelection(tab: ITabState, selection: IMirro
99
100
  * @internal
100
101
  */
101
102
  export declare function findAppliedFilterForStaged(tab: ITabState, staged: StagedFilter): FilterContextItem | undefined;
102
- /**
103
- * Filter state of a tab created while sync is on.
104
- *
105
- * @internal
106
- */
107
- export interface ISyncedTabSeed {
108
- readonly filterContextDefinition: IFilterContextDefinition;
109
- readonly attributeFilterDisplayForms: IAttributeDisplayFormMetadataObject[];
110
- readonly attributeFilterConfigs: IDashboardAttributeFilterConfig[];
111
- readonly dateFilterConfigs: IDashboardDateFilterConfigItem[];
112
- readonly measureValueFilterConfigs: IDashboardMeasureValueFilterConfig[];
113
- readonly filterGroupsConfig: IDashboardFilterGroupsConfig | undefined;
114
- }
115
- /**
116
- * Seeds a new tab with the applied filters of `sourceTab` and the configs that belong to them,
117
- * so every synced filter has a counterpart on the new tab. Cross-filtering virtual filters stay
118
- * on their own tab. `base` provides the title and description of the new filter context.
119
- *
120
- * @internal
121
- */
122
- export declare function seedSyncedTabFilters(sourceTab: ITabState, base: IFilterContextDefinition, crossFilteringLocalIdsByTab?: CrossFilteringLocalIdsByTab): ISyncedTabSeed;
123
103
  /**
124
104
  * Whether `value` can be stored on `targetFilter`.
125
105
  *
@@ -128,6 +108,10 @@ export declare function seedSyncedTabFilters(sourceTab: ITabState, base: IFilter
128
108
  * list-or-text filter, and cannot be applied to a list-only filter. An omitted selection type
129
109
  * means list-or-text, except a single-value list filter, which means list.
130
110
  *
111
+ * A text value is a value of one label, so it is valid only on a filter of the same display form.
112
+ * A filter that shows that label through its display-as label filters by another label and keeps
113
+ * its own value.
114
+ *
131
115
  * @internal
132
116
  */
133
117
  export declare function targetAcceptsAttributeFilterValue(targetTab: ITabState, targetFilter: DashboardAttributeFilterItem, value: DashboardAttributeFilterItem): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"filterSync.d.ts","sourceRoot":"","sources":["../../../../../src/model/store/tabs/filterContext/filterSync.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"filterSync.d.ts","sourceRoot":"","sources":["../../../../../src/model/store/tabs/filterContext/filterSync.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AAC1E,OAAO,EACH,KAAK,4BAA4B,EACjC,KAAK,iBAAiB,EAItB,KAAK,MAAM,EACX,KAAK,cAAc,EAgBtB,MAAM,qBAAqB,CAAC;AAI7B,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD,OAAO,EAAE,KAAK,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AAExE,KAAK,YAAY,GAAG,iBAAiB,GAAG,wBAAwB,CAAC;AAEjE;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACpC;;OAEG;IACH,QAAQ,CAAC,2BAA2B,CAAC,EAAE,2BAA2B,CAAC;CACtE;AAED;;;;;GAKG;AACH,MAAM,MAAM,2BAA2B,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAAC,CAAC;AAEtF;;;;;GAKG;AACH,wBAAgB,6BAA6B,CACzC,GAAG,EAAE,SAAS,EACd,eAAe,EAAE,MAAM,GAAG,SAAS,EACnC,2BAA2B,EAAE,2BAA2B,GAAG,SAAS,GACrE,OAAO,CAKT;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,qBAAqB,CACjC,SAAS,EAAE,SAAS,EACpB,YAAY,EAAE,iBAAiB,EAC/B,SAAS,EAAE,SAAS,EACpB,wBAAwB,CAAC,EAAE,wBAAwB,EAAE,EACrD,OAAO,CAAC,EAAE,uBAAuB,GAClC,iBAAiB,GAAG,SAAS,CA2C/B;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAC9B,GAAG,EAAE,SAAS,EACd,aAAa,EAAE,iBAAiB,GACjC,iBAAiB,GAAG,SAAS,CAyB/B;AAED;;;;GAIG;AACH,wBAAgB,2BAA2B,CACvC,MAAM,EAAE,4BAA4B,EACpC,eAAe,EAAE,MAAM,GACxB,4BAA4B,CAuB9B;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CACtC,QAAQ,EAAE,4BAA4B,EACtC,WAAW,EAAE,4BAA4B,GAC1C,4BAA4B,CA6B9B;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CACpC,MAAM,EAAE,iBAAiB,EACzB,MAAM,EAAE,iBAAiB,GAC1B,iBAAiB,CAyDnB;AAED;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;IAC/B,QAAQ,CAAC,OAAO,EAAE,SAAS,iBAAiB,EAAE,CAAC;IAC/C,QAAQ,CAAC,UAAU,EAAE,SAAS,uBAAuB,EAAE,CAAC;CAC3D;AAED;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACpC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,KAAK,EAAE,cAAc,GAAG,SAAS,CAAC;CAC9C;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,SAAS,EAAE,SAAS,EAAE,kBAAkB,GAAG,IAAI,CAuB1F;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CACtC,GAAG,EAAE,SAAS,EACd,MAAM,EAAE,YAAY,GACrB,iBAAiB,GAAG,SAAS,CAiB/B;AA4GD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iCAAiC,CAC7C,SAAS,EAAE,SAAS,EACpB,YAAY,EAAE,4BAA4B,EAC1C,KAAK,EAAE,4BAA4B,GACpC,OAAO,CAiBT"}