@gooddata/sdk-ui-dashboard 11.65.0-alpha.0 → 11.65.0-alpha.10

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 (430) hide show
  1. package/NOTICE +72077 -4
  2. package/esm/__version.d.ts +1 -1
  3. package/esm/__version.d.ts.map +1 -1
  4. package/esm/__version.js +1 -1
  5. package/esm/assets/type-csv-formatted.svg +1 -1
  6. package/esm/assets/type-csv-raw.svg +1 -1
  7. package/esm/index.d.ts +7 -4
  8. package/esm/index.d.ts.map +1 -1
  9. package/esm/index.js +3 -2
  10. package/esm/model/commandHandlers/dashboard/initializeDashboardHandler/resolveDashboardConfig.d.ts.map +1 -1
  11. package/esm/model/commandHandlers/dashboard/initializeDashboardHandler/resolveDashboardConfig.js +1 -3
  12. package/esm/model/commandHandlers/filterContext/attributeFilter/changeAttributeDisplayFormHandler.d.ts.map +1 -1
  13. package/esm/model/commandHandlers/filterContext/attributeFilter/changeAttributeDisplayFormHandler.js +8 -7
  14. package/esm/model/commandHandlers/filterContext/attributeFilter/changeAttributeFilterSelectionHandler.d.ts.map +1 -1
  15. package/esm/model/commandHandlers/filterContext/attributeFilter/changeAttributeFilterSelectionHandler.js +19 -28
  16. package/esm/model/commandHandlers/filterContext/attributeFilter/removeAttributeFiltersHandler.d.ts.map +1 -1
  17. package/esm/model/commandHandlers/filterContext/attributeFilter/removeAttributeFiltersHandler.js +4 -5
  18. package/esm/model/commandHandlers/filterContext/attributeFilter/replaceAttributeFilterItemSelectionHandler.d.ts.map +1 -1
  19. package/esm/model/commandHandlers/filterContext/attributeFilter/replaceAttributeFilterItemSelectionHandler.js +14 -15
  20. package/esm/model/commandHandlers/filterContext/attributeFilter/resolveDisplayFormMetadata.d.ts +4 -1
  21. package/esm/model/commandHandlers/filterContext/attributeFilter/resolveDisplayFormMetadata.d.ts.map +1 -1
  22. package/esm/model/commandHandlers/filterContext/attributeFilter/resolveDisplayFormMetadata.js +11 -2
  23. package/esm/model/commandHandlers/filterContext/changeFilterContextSelectionHandler.d.ts.map +1 -1
  24. package/esm/model/commandHandlers/filterContext/changeFilterContextSelectionHandler.js +23 -45
  25. package/esm/model/commandHandlers/filterContext/common.d.ts +6 -5
  26. package/esm/model/commandHandlers/filterContext/common.d.ts.map +1 -1
  27. package/esm/model/commandHandlers/filterContext/common.js +12 -18
  28. package/esm/model/commandHandlers/filterContext/dateFilter/changeDateFilterSelectionHandler.d.ts.map +1 -1
  29. package/esm/model/commandHandlers/filterContext/dateFilter/changeDateFilterSelectionHandler.js +30 -36
  30. package/esm/model/commandHandlers/filterContext/measureValueFilter/changeMeasureValueFilterConditionHandler.d.ts.map +1 -1
  31. package/esm/model/commandHandlers/filterContext/measureValueFilter/changeMeasureValueFilterConditionHandler.js +11 -17
  32. package/esm/model/commandHandlers/filterContext/measureValueFilter/changeMeasureValueFilterDimensionalityHandler.d.ts.map +1 -1
  33. package/esm/model/commandHandlers/filterContext/measureValueFilter/changeMeasureValueFilterDimensionalityHandler.js +7 -10
  34. package/esm/model/commandHandlers/filterContext/tabSync/expandActionsForTabSync.d.ts +15 -0
  35. package/esm/model/commandHandlers/filterContext/tabSync/expandActionsForTabSync.d.ts.map +1 -0
  36. package/esm/model/commandHandlers/filterContext/tabSync/expandActionsForTabSync.js +88 -0
  37. package/esm/model/commandHandlers/filterContext/tabSync/tabSyncRules.d.ts +11 -0
  38. package/esm/model/commandHandlers/filterContext/tabSync/tabSyncRules.d.ts.map +1 -0
  39. package/esm/model/commandHandlers/filterContext/tabSync/tabSyncRules.js +335 -0
  40. package/esm/model/commandHandlers/filterContext/tabSync/tabSyncSaga.d.ts +52 -0
  41. package/esm/model/commandHandlers/filterContext/tabSync/tabSyncSaga.d.ts.map +1 -0
  42. package/esm/model/commandHandlers/filterContext/tabSync/tabSyncSaga.js +60 -0
  43. package/esm/model/commandHandlers/filterContext/tabSync/tabSyncScope.d.ts +69 -0
  44. package/esm/model/commandHandlers/filterContext/tabSync/tabSyncScope.d.ts.map +1 -0
  45. package/esm/model/commandHandlers/filterContext/tabSync/tabSyncScope.js +2 -0
  46. package/esm/model/commandHandlers/parameters/changeParameterValuesHandler.d.ts +2 -1
  47. package/esm/model/commandHandlers/parameters/changeParameterValuesHandler.d.ts.map +1 -1
  48. package/esm/model/commandHandlers/parameters/changeParameterValuesHandler.js +41 -10
  49. package/esm/model/commands/parameters.d.ts +11 -1
  50. package/esm/model/commands/parameters.d.ts.map +1 -1
  51. package/esm/model/commands/parameters.js +2 -1
  52. package/esm/model/events/base.d.ts +1 -1
  53. package/esm/model/events/base.d.ts.map +1 -1
  54. package/esm/model/events/index.d.ts +2 -1
  55. package/esm/model/events/index.d.ts.map +1 -1
  56. package/esm/model/events/insightEditor.d.ts +128 -0
  57. package/esm/model/events/insightEditor.d.ts.map +1 -0
  58. package/esm/model/events/insightEditor.js +74 -0
  59. package/esm/model/queryServices/queryAttributeElements.js +1 -0
  60. package/esm/model/react/useInitializeDashboardStore.d.ts.map +1 -1
  61. package/esm/model/react/useInitializeDashboardStore.js +4 -9
  62. package/esm/model/store/config/configReducers.d.ts +4 -8
  63. package/esm/model/store/config/configReducers.d.ts.map +1 -1
  64. package/esm/model/store/config/configReducers.js +6 -12
  65. package/esm/model/store/config/configSelectors.d.ts +24 -0
  66. package/esm/model/store/config/configSelectors.d.ts.map +1 -1
  67. package/esm/model/store/config/configSelectors.js +30 -4
  68. package/esm/model/store/config/index.d.ts +2 -3
  69. package/esm/model/store/config/index.d.ts.map +1 -1
  70. package/esm/model/store/tabs/attributeFilterConfigs/attributeFilterConfigsReducers.d.ts +75 -5
  71. package/esm/model/store/tabs/attributeFilterConfigs/attributeFilterConfigsReducers.d.ts.map +1 -1
  72. package/esm/model/store/tabs/attributeFilterConfigs/attributeFilterConfigsReducers.js +35 -60
  73. package/esm/model/store/tabs/dateFilterConfigs/dateFilterConfigsReducers.js +1 -1
  74. package/esm/model/store/tabs/filterContext/filterContextReducers.d.ts +139 -31
  75. package/esm/model/store/tabs/filterContext/filterContextReducers.d.ts.map +1 -1
  76. package/esm/model/store/tabs/filterContext/filterContextReducers.js +314 -529
  77. package/esm/model/store/tabs/filterContext/filterSync.d.ts +35 -13
  78. package/esm/model/store/tabs/filterContext/filterSync.d.ts.map +1 -1
  79. package/esm/model/store/tabs/filterContext/filterSync.js +79 -58
  80. package/esm/model/store/tabs/index.d.ts +10 -12
  81. package/esm/model/store/tabs/index.d.ts.map +1 -1
  82. package/esm/model/store/tabs/layout/layoutReducers.d.ts +1 -0
  83. package/esm/model/store/tabs/layout/layoutReducers.d.ts.map +1 -1
  84. package/esm/model/store/tabs/measureValueFilterConfigs/measureValueFilterConfigsReducers.d.ts.map +1 -1
  85. package/esm/model/store/tabs/parameters/parametersReducers.d.ts +0 -5
  86. package/esm/model/store/tabs/parameters/parametersReducers.d.ts.map +1 -1
  87. package/esm/model/store/tabs/parameters/parametersReducers.js +8 -7
  88. package/esm/model/store/tabs/parameters/parametersSelectors.d.ts +7 -0
  89. package/esm/model/store/tabs/parameters/parametersSelectors.d.ts.map +1 -1
  90. package/esm/model/store/tabs/parameters/parametersSelectors.js +16 -0
  91. package/esm/model/store/tabs/tabsReducers.d.ts +8 -4
  92. package/esm/model/store/tabs/tabsReducers.d.ts.map +1 -1
  93. package/esm/model/store/tabs/tabsReducers.js +15 -18
  94. package/esm/model/store/tabs/tabsState.d.ts +0 -10
  95. package/esm/model/store/tabs/tabsState.d.ts.map +1 -1
  96. package/esm/model/store/tabs/tabsState.js +0 -20
  97. package/esm/model/store/ui/index.d.ts +2 -0
  98. package/esm/model/store/ui/index.d.ts.map +1 -1
  99. package/esm/model/store/ui/uiReducers.d.ts +6 -0
  100. package/esm/model/store/ui/uiReducers.d.ts.map +1 -1
  101. package/esm/model/store/ui/uiReducers.js +8 -0
  102. package/esm/model/store/ui/uiSelectors.d.ts +7 -0
  103. package/esm/model/store/ui/uiSelectors.d.ts.map +1 -1
  104. package/esm/model/store/ui/uiSelectors.js +6 -0
  105. package/esm/model/store/ui/uiState.d.ts +5 -0
  106. package/esm/model/store/ui/uiState.d.ts.map +1 -1
  107. package/esm/model/store/ui/uiState.js +1 -0
  108. package/esm/model/types/attributeFilterTypes.d.ts +5 -0
  109. package/esm/model/types/attributeFilterTypes.d.ts.map +1 -1
  110. package/esm/model/types/attributeFilterTypes.js +1 -1
  111. package/esm/model/types/commonTypes.d.ts +38 -22
  112. package/esm/model/types/commonTypes.d.ts.map +1 -1
  113. package/esm/model/types/insightEditorTypes.d.ts +43 -0
  114. package/esm/model/types/insightEditorTypes.d.ts.map +1 -0
  115. package/esm/model/types/insightEditorTypes.js +2 -0
  116. package/esm/model/utils/attributeFilterMatching.d.ts +10 -0
  117. package/esm/model/utils/attributeFilterMatching.d.ts.map +1 -1
  118. package/esm/model/utils/attributeFilterMatching.js +14 -3
  119. package/esm/model/utils/attributeFilterSelectionTypeCompatibility.d.ts +8 -0
  120. package/esm/model/utils/attributeFilterSelectionTypeCompatibility.d.ts.map +1 -1
  121. package/esm/model/utils/attributeFilterSelectionTypeCompatibility.js +14 -4
  122. package/esm/presentation/automations/alerting/hooks/useAttributeValuesFromExecResults.d.ts +33 -2
  123. package/esm/presentation/automations/alerting/hooks/useAttributeValuesFromExecResults.d.ts.map +1 -1
  124. package/esm/presentation/automations/alerting/hooks/useAttributeValuesFromExecResults.js +29 -13
  125. package/esm/presentation/automations/alerting/state/useAlertSupportedMetrics.d.ts.map +1 -1
  126. package/esm/presentation/automations/alerting/state/useAlertSupportedMetrics.js +3 -2
  127. package/esm/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/components/Attachments/DashboardAttachments.d.ts.map +1 -1
  128. package/esm/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/components/Attachments/DashboardAttachments.js +3 -3
  129. package/esm/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/components/Attachments/WidgetAttachments.d.ts.map +1 -1
  130. package/esm/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/components/Attachments/WidgetAttachments.js +5 -4
  131. package/esm/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/components/RecipientsSelect/LiveRegionLastSelectContainer.d.ts +9 -0
  132. package/esm/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/components/RecipientsSelect/LiveRegionLastSelectContainer.d.ts.map +1 -0
  133. package/esm/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/components/RecipientsSelect/LiveRegionLastSelectContainer.js +12 -0
  134. package/esm/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/components/RecipientsSelect/RecipientsSelect.d.ts.map +1 -1
  135. package/esm/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/components/RecipientsSelect/RecipientsSelect.js +3 -3
  136. package/esm/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/components/RecipientsSelect/RecipientsSelectRenderer.d.ts.map +1 -1
  137. package/esm/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/components/RecipientsSelect/RecipientsSelectRenderer.js +14 -7
  138. package/esm/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/components/RecipientsSelect/RecipientsSelectionDescription.d.ts +12 -0
  139. package/esm/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/components/RecipientsSelect/RecipientsSelectionDescription.d.ts.map +1 -0
  140. package/esm/presentation/automations/scheduledEmail/DefaultScheduledEmailDialog/components/RecipientsSelect/RecipientsSelectionDescription.js +30 -0
  141. package/esm/presentation/automations/scheduledEmail/utils/users.d.ts +1 -0
  142. package/esm/presentation/automations/scheduledEmail/utils/users.d.ts.map +1 -1
  143. package/esm/presentation/automations/scheduledEmail/utils/users.js +3 -0
  144. package/esm/presentation/automations/shared/automationFilters/utils.d.ts +4 -0
  145. package/esm/presentation/automations/shared/automationFilters/utils.d.ts.map +1 -1
  146. package/esm/presentation/automations/shared/automationFilters/utils.js +12 -5
  147. package/esm/presentation/dashboard/DashboardHeader/DashboardHeader.d.ts +1 -1
  148. package/esm/presentation/dashboard/DashboardHeader/DashboardHeader.d.ts.map +1 -1
  149. package/esm/presentation/dashboard/DashboardHeader/DashboardHeader.js +2 -11
  150. package/esm/presentation/dashboard/DashboardSidebar/CreationPanel.d.ts.map +1 -1
  151. package/esm/presentation/dashboard/DashboardSidebar/CreationPanel.js +10 -1
  152. package/esm/presentation/dashboard/DefaultDashboardContent/DashboardContentLoader.d.ts +5 -0
  153. package/esm/presentation/dashboard/DefaultDashboardContent/DashboardContentLoader.d.ts.map +1 -0
  154. package/esm/presentation/dashboard/DefaultDashboardContent/DashboardContentLoader.js +27 -0
  155. package/esm/presentation/dashboard/DefaultDashboardContent/DefaultDashboardMainContent.d.ts.map +1 -1
  156. package/esm/presentation/dashboard/DefaultDashboardContent/DefaultDashboardMainContent.js +7 -2
  157. package/esm/presentation/dashboard/components/DashboardAiComposingOverlay.d.ts +4 -0
  158. package/esm/presentation/dashboard/components/DashboardAiComposingOverlay.d.ts.map +1 -0
  159. package/esm/presentation/dashboard/components/DashboardAiComposingOverlay.js +151 -0
  160. package/esm/presentation/dashboard/components/DashboardInner.d.ts.map +1 -1
  161. package/esm/presentation/dashboard/components/DashboardInner.js +17 -14
  162. package/esm/presentation/dashboard/components/DashboardInteractionComposing.d.ts +8 -0
  163. package/esm/presentation/dashboard/components/DashboardInteractionComposing.d.ts.map +1 -0
  164. package/esm/presentation/dashboard/components/DashboardInteractionComposing.js +23 -0
  165. package/esm/presentation/dashboard/components/DashboardInteractionLock.d.ts +8 -0
  166. package/esm/presentation/dashboard/components/DashboardInteractionLock.d.ts.map +1 -0
  167. package/esm/presentation/dashboard/components/DashboardInteractionLock.js +29 -0
  168. package/esm/presentation/dashboard/components/DashboardScreenSizeContext.d.ts.map +1 -1
  169. package/esm/presentation/dashboard/components/DashboardScreenSizeContext.js +10 -7
  170. package/esm/presentation/dashboard/components/ToastMessages.d.ts.map +1 -1
  171. package/esm/presentation/dashboard/components/ToastMessages.js +6 -3
  172. package/esm/presentation/dashboard/components/useEditModeLayoutNoteMessages.d.ts +6 -0
  173. package/esm/presentation/dashboard/components/useEditModeLayoutNoteMessages.d.ts.map +1 -0
  174. package/esm/presentation/dashboard/components/useEditModeLayoutNoteMessages.js +48 -0
  175. package/esm/presentation/dashboard/hooks/useDashboard.d.ts.map +1 -1
  176. package/esm/presentation/dashboard/hooks/useDashboard.js +3 -2
  177. package/esm/presentation/dashboard/types.d.ts +5 -0
  178. package/esm/presentation/dashboard/types.d.ts.map +1 -1
  179. package/esm/presentation/dragAndDrop/draggableWidget/AddDashboardLayoutWidgetButton.d.ts.map +1 -1
  180. package/esm/presentation/dragAndDrop/draggableWidget/AddDashboardLayoutWidgetButton.js +2 -4
  181. package/esm/presentation/dragAndDrop/draggableWidget/AddRichTextWidgetButton.d.ts.map +1 -1
  182. package/esm/presentation/dragAndDrop/draggableWidget/AddRichTextWidgetButton.js +3 -3
  183. package/esm/presentation/dragAndDrop/draggableWidget/AddVisualizationSwitcherWidgetButton.d.ts.map +1 -1
  184. package/esm/presentation/dragAndDrop/draggableWidget/AddVisualizationSwitcherWidgetButton.js +2 -4
  185. package/esm/presentation/drill/utils/drillDownUtils.d.ts.map +1 -1
  186. package/esm/presentation/drill/utils/drillDownUtils.js +3 -2
  187. package/esm/presentation/export/hooks/useDashboardRelatedFilters.d.ts +8 -1
  188. package/esm/presentation/export/hooks/useDashboardRelatedFilters.d.ts.map +1 -1
  189. package/esm/presentation/export/hooks/useDashboardRelatedFilters.js +21 -5
  190. package/esm/presentation/filterBar/attributeFilter/DefaultDashboardAttributeFilter.d.ts.map +1 -1
  191. package/esm/presentation/filterBar/attributeFilter/DefaultDashboardAttributeFilter.js +3 -2
  192. package/esm/presentation/filterBar/attributeFilter/addAttributeFilter/AddAttributeFilterPlaceholder.d.ts.map +1 -1
  193. package/esm/presentation/filterBar/attributeFilter/addAttributeFilter/AddAttributeFilterPlaceholder.js +3 -2
  194. package/esm/presentation/filterBar/attributeFilter/addAttributeFilter/attributeListItemTooltip/AttributeListItemTooltip.d.ts.map +1 -1
  195. package/esm/presentation/filterBar/attributeFilter/addAttributeFilter/attributeListItemTooltip/AttributeListItemTooltip.js +4 -1
  196. package/esm/presentation/filterBar/attributeFilter/addAttributeFilter/attributeListItemTooltip/AttributeListItemTooltipContent.d.ts +6 -2
  197. package/esm/presentation/filterBar/attributeFilter/addAttributeFilter/attributeListItemTooltip/AttributeListItemTooltipContent.d.ts.map +1 -1
  198. package/esm/presentation/filterBar/attributeFilter/addAttributeFilter/attributeListItemTooltip/AttributeListItemTooltipContent.js +8 -4
  199. package/esm/presentation/filterBar/filterBar/filterViews/FilterViewDeleteConfirm.d.ts +2 -1
  200. package/esm/presentation/filterBar/filterBar/filterViews/FilterViewDeleteConfirm.d.ts.map +1 -1
  201. package/esm/presentation/filterBar/filterBar/filterViews/FilterViewDeleteConfirm.js +2 -2
  202. package/esm/presentation/filterBar/filterBar/filterViews/FilterViewsList.d.ts.map +1 -1
  203. package/esm/presentation/filterBar/filterBar/filterViews/FilterViewsList.js +11 -5
  204. package/esm/presentation/filterBar/filterBar/hooks/useResetFiltersButton.d.ts.map +1 -1
  205. package/esm/presentation/filterBar/filterBar/hooks/useResetFiltersButton.js +4 -1
  206. package/esm/presentation/insightEditor/InsightEditorContent.d.ts +26 -0
  207. package/esm/presentation/insightEditor/InsightEditorContent.d.ts.map +1 -0
  208. package/esm/presentation/insightEditor/InsightEditorContent.js +158 -0
  209. package/esm/presentation/insightEditor/InsightEditorCreatePanelItem.d.ts +7 -0
  210. package/esm/presentation/insightEditor/InsightEditorCreatePanelItem.d.ts.map +1 -0
  211. package/esm/presentation/insightEditor/InsightEditorCreatePanelItem.js +25 -0
  212. package/esm/presentation/insightEditor/InsightEditorOverlay.d.ts +6 -0
  213. package/esm/presentation/insightEditor/InsightEditorOverlay.d.ts.map +1 -0
  214. package/esm/presentation/insightEditor/InsightEditorOverlay.js +110 -0
  215. package/esm/presentation/insightEditor/InsightEditorPermissionsContext.d.ts +10 -0
  216. package/esm/presentation/insightEditor/InsightEditorPermissionsContext.d.ts.map +1 -0
  217. package/esm/presentation/insightEditor/InsightEditorPermissionsContext.js +18 -0
  218. package/esm/presentation/insightEditor/InsightEditorPlaceholder.d.ts +7 -0
  219. package/esm/presentation/insightEditor/InsightEditorPlaceholder.d.ts.map +1 -0
  220. package/esm/presentation/insightEditor/InsightEditorPlaceholder.js +15 -0
  221. package/esm/presentation/insightEditor/filterContext/attributeFilters.d.ts +4 -0
  222. package/esm/presentation/insightEditor/filterContext/attributeFilters.d.ts.map +1 -0
  223. package/esm/presentation/insightEditor/filterContext/attributeFilters.js +115 -0
  224. package/esm/presentation/insightEditor/filterContext/dateFilters.d.ts +5 -0
  225. package/esm/presentation/insightEditor/filterContext/dateFilters.d.ts.map +1 -0
  226. package/esm/presentation/insightEditor/filterContext/dateFilters.js +117 -0
  227. package/esm/presentation/insightEditor/filterContext/filterIntersection.d.ts +7 -0
  228. package/esm/presentation/insightEditor/filterContext/filterIntersection.d.ts.map +1 -0
  229. package/esm/presentation/insightEditor/filterContext/filterIntersection.js +149 -0
  230. package/esm/presentation/insightEditor/filterContext/insightFilterContext.d.ts +26 -0
  231. package/esm/presentation/insightEditor/filterContext/insightFilterContext.d.ts.map +1 -0
  232. package/esm/presentation/insightEditor/filterContext/insightFilterContext.js +72 -0
  233. package/esm/presentation/insightEditor/filterContext/measureValueFilters.d.ts +20 -0
  234. package/esm/presentation/insightEditor/filterContext/measureValueFilters.d.ts.map +1 -0
  235. package/esm/presentation/insightEditor/filterContext/measureValueFilters.js +76 -0
  236. package/esm/presentation/insightEditor/filterContext/objQualifiers.d.ts +11 -0
  237. package/esm/presentation/insightEditor/filterContext/objQualifiers.d.ts.map +1 -0
  238. package/esm/presentation/insightEditor/filterContext/objQualifiers.js +18 -0
  239. package/esm/presentation/insightEditor/insightEditorEscapeGuard.d.ts +18 -0
  240. package/esm/presentation/insightEditor/insightEditorEscapeGuard.d.ts.map +1 -0
  241. package/esm/presentation/insightEditor/insightEditorEscapeGuard.js +24 -0
  242. package/esm/presentation/insightEditor/insightEditorRoute.d.ts +34 -0
  243. package/esm/presentation/insightEditor/insightEditorRoute.d.ts.map +1 -0
  244. package/esm/presentation/insightEditor/insightEditorRoute.js +48 -0
  245. package/esm/presentation/insightEditor/types.d.ts +7 -0
  246. package/esm/presentation/insightEditor/types.d.ts.map +1 -0
  247. package/esm/presentation/insightEditor/types.js +2 -0
  248. package/esm/presentation/insightEditor/useCanCreateInsightInEditor.d.ts +5 -0
  249. package/esm/presentation/insightEditor/useCanCreateInsightInEditor.d.ts.map +1 -0
  250. package/esm/presentation/insightEditor/useCanCreateInsightInEditor.js +14 -0
  251. package/esm/presentation/insightEditor/useExploreFilterTransfer.d.ts +21 -0
  252. package/esm/presentation/insightEditor/useExploreFilterTransfer.d.ts.map +1 -0
  253. package/esm/presentation/insightEditor/useExploreFilterTransfer.js +193 -0
  254. package/esm/presentation/insightEditor/useInsightEditPermissions.d.ts +17 -0
  255. package/esm/presentation/insightEditor/useInsightEditPermissions.d.ts.map +1 -0
  256. package/esm/presentation/insightEditor/useInsightEditPermissions.js +42 -0
  257. package/esm/presentation/insightEditor/useInsightEditorMenuItems.d.ts +23 -0
  258. package/esm/presentation/insightEditor/useInsightEditorMenuItems.d.ts.map +1 -0
  259. package/esm/presentation/insightEditor/useInsightEditorMenuItems.js +126 -0
  260. package/esm/presentation/insightEditor/useInsightEditorSession.d.ts +19 -0
  261. package/esm/presentation/insightEditor/useInsightEditorSession.d.ts.map +1 -0
  262. package/esm/presentation/insightEditor/useInsightEditorSession.js +141 -0
  263. package/esm/presentation/insightList/InsightList.d.ts.map +1 -1
  264. package/esm/presentation/insightList/InsightList.js +10 -5
  265. package/esm/presentation/localization/bundles/de-DE.localization-bundle.d.ts +6 -0
  266. package/esm/presentation/localization/bundles/de-DE.localization-bundle.d.ts.map +1 -1
  267. package/esm/presentation/localization/bundles/de-DE.localization-bundle.js +48 -42
  268. package/esm/presentation/localization/bundles/en-AU.localization-bundle.d.ts +6 -0
  269. package/esm/presentation/localization/bundles/en-AU.localization-bundle.d.ts.map +1 -1
  270. package/esm/presentation/localization/bundles/en-AU.localization-bundle.js +6 -0
  271. package/esm/presentation/localization/bundles/en-GB.localization-bundle.d.ts +6 -0
  272. package/esm/presentation/localization/bundles/en-GB.localization-bundle.d.ts.map +1 -1
  273. package/esm/presentation/localization/bundles/en-GB.localization-bundle.js +11 -5
  274. package/esm/presentation/localization/bundles/en-US.localization-bundle.d.ts +64 -0
  275. package/esm/presentation/localization/bundles/en-US.localization-bundle.d.ts.map +1 -1
  276. package/esm/presentation/localization/bundles/en-US.localization-bundle.js +64 -0
  277. package/esm/presentation/localization/bundles/es-419.localization-bundle.d.ts +6 -0
  278. package/esm/presentation/localization/bundles/es-419.localization-bundle.d.ts.map +1 -1
  279. package/esm/presentation/localization/bundles/es-419.localization-bundle.js +6 -0
  280. package/esm/presentation/localization/bundles/es-ES.localization-bundle.d.ts +6 -0
  281. package/esm/presentation/localization/bundles/es-ES.localization-bundle.d.ts.map +1 -1
  282. package/esm/presentation/localization/bundles/es-ES.localization-bundle.js +6 -0
  283. package/esm/presentation/localization/bundles/fi-FI.localization-bundle.d.ts +6 -0
  284. package/esm/presentation/localization/bundles/fi-FI.localization-bundle.d.ts.map +1 -1
  285. package/esm/presentation/localization/bundles/fi-FI.localization-bundle.js +6 -0
  286. package/esm/presentation/localization/bundles/fr-CA.localization-bundle.d.ts +6 -0
  287. package/esm/presentation/localization/bundles/fr-CA.localization-bundle.d.ts.map +1 -1
  288. package/esm/presentation/localization/bundles/fr-CA.localization-bundle.js +6 -0
  289. package/esm/presentation/localization/bundles/fr-FR.localization-bundle.d.ts +6 -0
  290. package/esm/presentation/localization/bundles/fr-FR.localization-bundle.d.ts.map +1 -1
  291. package/esm/presentation/localization/bundles/fr-FR.localization-bundle.js +187 -181
  292. package/esm/presentation/localization/bundles/id-ID.localization-bundle.d.ts +6 -0
  293. package/esm/presentation/localization/bundles/id-ID.localization-bundle.d.ts.map +1 -1
  294. package/esm/presentation/localization/bundles/id-ID.localization-bundle.js +6 -0
  295. package/esm/presentation/localization/bundles/it-IT.localization-bundle.d.ts +6 -0
  296. package/esm/presentation/localization/bundles/it-IT.localization-bundle.d.ts.map +1 -1
  297. package/esm/presentation/localization/bundles/it-IT.localization-bundle.js +6 -0
  298. package/esm/presentation/localization/bundles/ja-JP.localization-bundle.d.ts +6 -0
  299. package/esm/presentation/localization/bundles/ja-JP.localization-bundle.d.ts.map +1 -1
  300. package/esm/presentation/localization/bundles/ja-JP.localization-bundle.js +6 -0
  301. package/esm/presentation/localization/bundles/ko-KR.localization-bundle.d.ts +6 -0
  302. package/esm/presentation/localization/bundles/ko-KR.localization-bundle.d.ts.map +1 -1
  303. package/esm/presentation/localization/bundles/ko-KR.localization-bundle.js +6 -0
  304. package/esm/presentation/localization/bundles/nl-NL.localization-bundle.d.ts +6 -0
  305. package/esm/presentation/localization/bundles/nl-NL.localization-bundle.d.ts.map +1 -1
  306. package/esm/presentation/localization/bundles/nl-NL.localization-bundle.js +6 -0
  307. package/esm/presentation/localization/bundles/pl-PL.localization-bundle.d.ts +6 -0
  308. package/esm/presentation/localization/bundles/pl-PL.localization-bundle.d.ts.map +1 -1
  309. package/esm/presentation/localization/bundles/pl-PL.localization-bundle.js +6 -0
  310. package/esm/presentation/localization/bundles/pt-BR.localization-bundle.d.ts +6 -0
  311. package/esm/presentation/localization/bundles/pt-BR.localization-bundle.d.ts.map +1 -1
  312. package/esm/presentation/localization/bundles/pt-BR.localization-bundle.js +6 -0
  313. package/esm/presentation/localization/bundles/pt-PT.localization-bundle.d.ts +6 -0
  314. package/esm/presentation/localization/bundles/pt-PT.localization-bundle.d.ts.map +1 -1
  315. package/esm/presentation/localization/bundles/pt-PT.localization-bundle.js +6 -0
  316. package/esm/presentation/localization/bundles/ru-RU.localization-bundle.d.ts +6 -0
  317. package/esm/presentation/localization/bundles/ru-RU.localization-bundle.d.ts.map +1 -1
  318. package/esm/presentation/localization/bundles/ru-RU.localization-bundle.js +6 -0
  319. package/esm/presentation/localization/bundles/sl-SI.localization-bundle.d.ts +6 -0
  320. package/esm/presentation/localization/bundles/sl-SI.localization-bundle.d.ts.map +1 -1
  321. package/esm/presentation/localization/bundles/sl-SI.localization-bundle.js +6 -0
  322. package/esm/presentation/localization/bundles/th-TH.localization-bundle.d.ts +6 -0
  323. package/esm/presentation/localization/bundles/th-TH.localization-bundle.d.ts.map +1 -1
  324. package/esm/presentation/localization/bundles/th-TH.localization-bundle.js +6 -0
  325. package/esm/presentation/localization/bundles/tr-TR.localization-bundle.d.ts +6 -0
  326. package/esm/presentation/localization/bundles/tr-TR.localization-bundle.d.ts.map +1 -1
  327. package/esm/presentation/localization/bundles/tr-TR.localization-bundle.js +6 -0
  328. package/esm/presentation/localization/bundles/uk-UA.localization-bundle.d.ts +6 -0
  329. package/esm/presentation/localization/bundles/uk-UA.localization-bundle.d.ts.map +1 -1
  330. package/esm/presentation/localization/bundles/uk-UA.localization-bundle.js +6 -0
  331. package/esm/presentation/localization/bundles/vi-VN.localization-bundle.d.ts +6 -0
  332. package/esm/presentation/localization/bundles/vi-VN.localization-bundle.d.ts.map +1 -1
  333. package/esm/presentation/localization/bundles/vi-VN.localization-bundle.js +6 -0
  334. package/esm/presentation/localization/bundles/zh-HK.localization-bundle.d.ts +6 -0
  335. package/esm/presentation/localization/bundles/zh-HK.localization-bundle.d.ts.map +1 -1
  336. package/esm/presentation/localization/bundles/zh-HK.localization-bundle.js +6 -0
  337. package/esm/presentation/localization/bundles/zh-Hans.localization-bundle.d.ts +6 -0
  338. package/esm/presentation/localization/bundles/zh-Hans.localization-bundle.d.ts.map +1 -1
  339. package/esm/presentation/localization/bundles/zh-Hans.localization-bundle.js +6 -0
  340. package/esm/presentation/localization/bundles/zh-Hant.localization-bundle.d.ts +6 -0
  341. package/esm/presentation/localization/bundles/zh-Hant.localization-bundle.d.ts.map +1 -1
  342. package/esm/presentation/localization/bundles/zh-Hant.localization-bundle.js +7 -1
  343. package/esm/presentation/topBar/buttonBar/button/editButton/DefaultEditButton.d.ts.map +1 -1
  344. package/esm/presentation/topBar/buttonBar/button/editButton/DefaultEditButton.js +2 -4
  345. package/esm/presentation/topBar/buttonBar/button/saveAsButton/DefaultSaveAsNewButton.d.ts.map +1 -1
  346. package/esm/presentation/topBar/buttonBar/button/saveAsButton/DefaultSaveAsNewButton.js +3 -2
  347. package/esm/presentation/topBar/buttonBar/button/saveButton/DefaultSaveButton.d.ts.map +1 -1
  348. package/esm/presentation/topBar/buttonBar/button/saveButton/DefaultSaveButton.js +3 -2
  349. package/esm/presentation/topBar/buttonBar/button/settingButton/DefaultSettingButton.d.ts.map +1 -1
  350. package/esm/presentation/topBar/buttonBar/button/settingButton/DefaultSettingButton.js +3 -2
  351. package/esm/presentation/topBar/buttonBar/button/shareButton/DefaultShareButton.d.ts.map +1 -1
  352. package/esm/presentation/topBar/buttonBar/button/shareButton/DefaultShareButton.js +3 -2
  353. package/esm/presentation/topBar/title/EditableTitle.d.ts.map +1 -1
  354. package/esm/presentation/topBar/title/EditableTitle.js +6 -0
  355. package/esm/presentation/widget/insight/DefaultDashboardInsightComponentSetFactory.d.ts +1 -1
  356. package/esm/presentation/widget/insight/DefaultDashboardInsightComponentSetFactory.d.ts.map +1 -1
  357. package/esm/presentation/widget/insight/DefaultDashboardInsightComponentSetFactory.js +13 -1
  358. package/esm/presentation/widget/insightMenu/DefaultDashboardInsightMenu/DashboardInsightMenu/index.d.ts.map +1 -1
  359. package/esm/presentation/widget/insightMenu/DefaultDashboardInsightMenu/DashboardInsightMenu/index.js +10 -1
  360. package/esm/presentation/widget/richText/EditModeDashboardRichText.js +1 -1
  361. package/esm/presentation/widget/visualizationSwitcher/EditModeDashboardVisualizationSwitcher.js +1 -1
  362. package/esm/presentation/widget/visualizationSwitcher/configuration/ToolbarTop.js +2 -2
  363. package/esm/presentation/widget/widget/InsightWidget/useEditableInsightMenu.d.ts.map +1 -1
  364. package/esm/presentation/widget/widget/InsightWidget/useEditableInsightMenu.js +5 -1
  365. package/esm/presentation/widget/widget/InsightWidget/useInsightMenu.d.ts.map +1 -1
  366. package/esm/presentation/widget/widget/InsightWidget/useInsightMenu.js +4 -1
  367. package/esm/sdk-ui-dashboard.d.ts +528 -68
  368. package/package.json +23 -21
  369. package/styles/css/alerting.css +1 -1
  370. package/styles/css/alerting.css.map +1 -1
  371. package/styles/css/attributeFilterConfig.css +3 -3
  372. package/styles/css/automationFilters.css +1 -1
  373. package/styles/css/configurationPanel.css +2 -2
  374. package/styles/css/configurationPanel.css.map +1 -1
  375. package/styles/css/dashboard.css +149 -86
  376. package/styles/css/dashboard.css.map +1 -1
  377. package/styles/css/dashboardContentLoader.css +45 -0
  378. package/styles/css/dashboardContentLoader.css.map +1 -0
  379. package/styles/css/dashboardNestedLayoutToolbar.css.map +1 -1
  380. package/styles/css/dashboardNestedLayoutWidget.css +1 -1
  381. package/styles/css/dashboardSettingsDialog.css +1 -1
  382. package/styles/css/dragAndDrop.css +0 -8
  383. package/styles/css/dragAndDrop.css.map +1 -1
  384. package/styles/css/drillConfigPanel.css +7 -7
  385. package/styles/css/drillConfigPanel.css.map +1 -1
  386. package/styles/css/filterBar.css +4 -4
  387. package/styles/css/filterBar.css.map +1 -1
  388. package/styles/css/grouped-navigation.css +2 -2
  389. package/styles/css/grouped-navigation.css.map +1 -1
  390. package/styles/css/icons.css.map +1 -1
  391. package/styles/css/insightConfiguration.css +1 -1
  392. package/styles/css/insightConfiguration.css.map +1 -1
  393. package/styles/css/insightEditor.css +46 -0
  394. package/styles/css/insightEditor.css.map +1 -0
  395. package/styles/css/kpi.css +2 -2
  396. package/styles/css/kpi.css.map +1 -1
  397. package/styles/css/kpi_alert_dialog.css +2 -2
  398. package/styles/css/layout.css +5 -5
  399. package/styles/css/layout.css.map +1 -1
  400. package/styles/css/main.css +343 -218
  401. package/styles/css/main.css.map +1 -1
  402. package/styles/css/notifications_channels_dialog.css +2 -2
  403. package/styles/css/notifications_channels_dialog.css.map +1 -1
  404. package/styles/css/resizing.css.map +1 -1
  405. package/styles/css/richTextWidget.css.map +1 -1
  406. package/styles/css/saveAsDialog.css.map +1 -1
  407. package/styles/css/sidebar.css +35 -10
  408. package/styles/css/sidebar.css.map +1 -1
  409. package/styles/css/topBar.css.map +1 -1
  410. package/styles/css/visualization.css.map +1 -1
  411. package/styles/css/visualizationSwitcherHeader.css.map +1 -1
  412. package/styles/css/visualizationSwitcherToolbar.css +1 -1
  413. package/styles/css/visualizationSwitcherToolbar.css.map +1 -1
  414. package/styles/css/visualizationSwitcherWidget.css +1 -1
  415. package/styles/css/visualizationSwitcherWidget.css.map +1 -1
  416. package/styles/scss/_variables.scss +3 -2
  417. package/styles/scss/_zIndexes.scss +4 -0
  418. package/styles/scss/attributeFilterConfig.scss +1 -1
  419. package/styles/scss/configurationPanel.scss +1 -1
  420. package/styles/scss/dashboard.scss +113 -94
  421. package/styles/scss/dashboardContentLoader.scss +45 -0
  422. package/styles/scss/dragAndDrop.scss +2 -9
  423. package/styles/scss/drillConfigPanel.scss +3 -3
  424. package/styles/scss/insightEditor.scss +53 -0
  425. package/styles/scss/layout.scss +1 -1
  426. package/styles/scss/main.scss +1 -0
  427. package/styles/scss/sidebar.scss +47 -12
  428. package/esm/presentation/dashboard/components/DashboardSkeleton.d.ts +0 -5
  429. package/esm/presentation/dashboard/components/DashboardSkeleton.d.ts.map +0 -1
  430. package/esm/presentation/dashboard/components/DashboardSkeleton.js +0 -20
@@ -1,11 +1,35 @@
1
1
  // (C) 2021-2026 GoodData Corporation
2
2
  import { invariant } from "ts-invariant";
3
- import { areObjRefsEqual, attributeElementsIsEmpty, dashboardAttributeFilterItemLocalIdentifier, dashboardFilterLocalIdentifier, isAllTimeDashboardDateFilter, isAttributeElementsByRef, isDashboardArbitraryAttributeFilter, isDashboardAttributeFilter, isDashboardAttributeFilterItem, isDashboardCommonDateFilter, isDashboardDateFilter, isDashboardMatchAttributeFilter, isDashboardMeasureValueFilter, newAllTimeDashboardDateFilter, } from "@gooddata/sdk-model";
3
+ import { areObjRefsEqual, attributeElementsIsEmpty, dashboardAttributeFilterItemDisplayForm, dashboardAttributeFilterItemLocalIdentifier, dashboardFilterLocalIdentifier, isAttributeElementsByRef, isDashboardArbitraryAttributeFilter, isDashboardAttributeFilter, isDashboardAttributeFilterItem, isDashboardCommonDateFilter, isDashboardDateFilter, isDashboardDateFilterWithDimension, isDashboardMatchAttributeFilter, isDashboardMeasureValueFilter, isIdentifierRef, newAllTimeDashboardDateFilter, } from "@gooddata/sdk-model";
4
+ import { isDisplayFormMetadataReferencedBy } from "../../../utils/attributeFilterMatching.js";
4
5
  import { generateFilterLocalIdentifier, generateMeasureValueFilterLocalIdentifier, } from "../../_infra/generators.js";
5
- import { getActiveTab, getTabOrActive, getTabsToMutate, } from "../tabsState.js";
6
- import { filterContextInitialState } from "./filterContextState.js";
6
+ import { getActiveTab, getTabOrActive } from "../tabsState.js";
7
+ import { filterContextInitialState, } from "./filterContextState.js";
7
8
  import { applyFilterContext, initializeFilterContext } from "./filterContextUtils.js";
8
- import { findCounterpartFilter, findOriginalFilter, isCrossFilteringVirtualFilter, preserveFilterDependencies, retargetAttributeFilterItem, } from "./filterSync.js";
9
+ import { findOriginalFilter, preserveFilterDependencies } from "./filterSync.js";
10
+ /**
11
+ * Filter context of the tab addressed by `tabLocalIdentifier`, or of the active tab when omitted.
12
+ * Initializes an empty filter context on a tab that has none.
13
+ */
14
+ function getTabFilterContext(state, tabLocalIdentifier) {
15
+ const tab = getTabOrActive(state, tabLocalIdentifier);
16
+ if (!tab) {
17
+ return undefined;
18
+ }
19
+ if (!tab.filterContext) {
20
+ tab.filterContext = { ...filterContextInitialState };
21
+ }
22
+ return { tab, filterContext: tab.filterContext };
23
+ }
24
+ function getEditableFilterContext(state, tabLocalIdentifier) {
25
+ const target = getTabFilterContext(state, tabLocalIdentifier);
26
+ if (!target) {
27
+ return undefined;
28
+ }
29
+ const definition = target.filterContext.filterContextDefinition;
30
+ invariant(definition, "Attempt to edit uninitialized filter context");
31
+ return { ...target, definition };
32
+ }
9
33
  const setFilterContext = (state, action) => {
10
34
  const activeTab = getActiveTab(state);
11
35
  if (!activeTab) {
@@ -46,42 +70,34 @@ const updateFilterContextIdentityForTab = (state, action) => {
46
70
  }
47
71
  tab.filterContext.filterContextIdentity = filterContextIdentity;
48
72
  };
49
- //
50
- //
51
- //
52
73
  const removeAttributeFilterDisplayForms = (state, action) => {
53
- const activeTab = getActiveTab(state);
54
- if (!activeTab) {
74
+ const { displayForm, tabLocalIdentifier } = action.payload;
75
+ const target = getTabFilterContext(state, tabLocalIdentifier);
76
+ if (!target) {
55
77
  return;
56
78
  }
57
- if (!activeTab.filterContext) {
58
- activeTab.filterContext = { ...filterContextInitialState };
59
- }
60
- invariant(activeTab.filterContext.attributeFilterDisplayForms, "attempting to work with uninitialized state");
61
- activeTab.filterContext.attributeFilterDisplayForms =
62
- activeTab.filterContext.attributeFilterDisplayForms.filter((df) => {
63
- return !areObjRefsEqual(df, action.payload);
64
- });
79
+ const { filterContext } = target;
80
+ invariant(filterContext.attributeFilterDisplayForms, "attempting to work with uninitialized state");
81
+ // A cross-filtering virtual filter shares its display form with the dashboard filter it duplicates.
82
+ const usedDisplayForms = (filterContext.filterContextDefinition?.filters ?? [])
83
+ .filter(isDashboardAttributeFilterItem)
84
+ .map(dashboardAttributeFilterItemDisplayForm);
85
+ filterContext.attributeFilterDisplayForms = filterContext.attributeFilterDisplayForms.filter((df) => !isDisplayFormMetadataReferencedBy(df, displayForm) ||
86
+ usedDisplayForms.some((used) => isDisplayFormMetadataReferencedBy(df, used)));
65
87
  };
66
88
  const addAttributeFilterDisplayForm = (state, action) => {
67
89
  // Handle both old and new payload formats for backward compatibility
68
90
  const displayForm = "displayForm" in action.payload ? action.payload.displayForm : action.payload;
69
91
  const tabLocalIdentifier = "tabLocalIdentifier" in action.payload ? action.payload.tabLocalIdentifier : undefined;
70
- const targetTab = getTabOrActive(state, tabLocalIdentifier);
71
- if (!targetTab) {
92
+ const target = getTabFilterContext(state, tabLocalIdentifier);
93
+ if (!target) {
72
94
  return;
73
95
  }
74
- if (!targetTab.filterContext) {
75
- targetTab.filterContext = { ...filterContextInitialState };
76
- }
77
- invariant(targetTab.filterContext.attributeFilterDisplayForms, "attempting to work with uninitialized state");
96
+ const { filterContext } = target;
97
+ invariant(filterContext.attributeFilterDisplayForms, "attempting to work with uninitialized state");
78
98
  // if there is already a display form with the same ref, replace it
79
- const existing = targetTab.filterContext.attributeFilterDisplayForms.find((df) => areObjRefsEqual(df, displayForm.ref));
80
- if (existing) {
81
- targetTab.filterContext.attributeFilterDisplayForms =
82
- targetTab.filterContext.attributeFilterDisplayForms.filter((df) => !areObjRefsEqual(df, displayForm));
83
- }
84
- targetTab.filterContext.attributeFilterDisplayForms.push(displayForm);
99
+ filterContext.attributeFilterDisplayForms = filterContext.attributeFilterDisplayForms.filter((df) => !isDisplayFormMetadataReferencedBy(df, displayForm.ref));
100
+ filterContext.attributeFilterDisplayForms.push(displayForm);
85
101
  };
86
102
  //
87
103
  //
@@ -92,88 +108,19 @@ const setPreloadedAttributesWithReferences = (state, action) => {
92
108
  state.attributesWithReferences = action.payload;
93
109
  };
94
110
  const upsertDateFilter = (state, action) => {
95
- const { tabLocalIdentifier, enablePersistentFiltersAcrossTabs, isWorkingSelectionChange } = action.payload;
96
- const tabs = getTabsToMutate(state, tabLocalIdentifier, enablePersistentFiltersAcrossTabs, isWorkingSelectionChange);
97
- const source = tabs[0];
98
- if (!source) {
111
+ const tab = getTabOrActive(state, action.payload.tabLocalIdentifier);
112
+ if (!tab) {
99
113
  return;
100
114
  }
101
- upsertDateFilterOnTab(source, action.payload, true);
102
- for (const tab of tabs.slice(1)) {
103
- const payload = action.payload.restoreTargetOriginal
104
- ? restoredDateFilterPayload(tab, action.payload)
105
- : action.payload;
106
- if (!payload) {
107
- continue;
108
- }
109
- upsertDateFilterOnTab(tab, payload, false);
110
- }
115
+ upsertDateFilterOnTab(tab, action.payload);
111
116
  };
112
- /**
113
- * Saved date filter for a non-source tab during reset.
114
- * A common date filter with no saved original is all time, which is stored as the filter's absence.
115
- * A dimension date filter with no counterpart, or no saved original, is left unchanged.
116
- */
117
- function restoredDateFilterPayload(tab, payload) {
118
- const applied = findAppliedDateFilter(tab, payload.dataSet);
119
- if (!applied && payload.dataSet) {
120
- return undefined;
121
- }
122
- const original = findOriginalFilter(tab, applied ?? {
123
- dateFilter: { type: "relative", granularity: "GDC.time.date" },
124
- });
125
- if (isDashboardDateFilter(original)) {
126
- return toUpsertDateFilterPayload(original, payload);
127
- }
128
- if (!payload.dataSet) {
129
- return { type: "allTime" };
130
- }
131
- return undefined;
132
- }
133
- function findAppliedDateFilter(tab, dataSet) {
134
- const filters = tab.filterContext?.filterContextDefinition?.filters;
135
- if (!filters) {
136
- return undefined;
137
- }
138
- if (dataSet) {
139
- return filters.find((item) => isDashboardDateFilter(item) && areObjRefsEqual(item.dateFilter.dataSet, dataSet));
140
- }
141
- return filters.find(isDashboardCommonDateFilter);
142
- }
143
- function toUpsertDateFilterPayload(filter, source) {
144
- const { dataSet, localIdentifier, emptyValueHandling, boundedFilter, type, granularity, from, to } = filter.dateFilter;
145
- const shared = {
146
- ...(dataSet ? { dataSet } : {}),
147
- ...(localIdentifier ? { localIdentifier } : {}),
148
- ...(emptyValueHandling ? { emptyValueHandling } : {}),
149
- ...(source.isWorkingSelectionChange ? { isWorkingSelectionChange: true } : {}),
150
- ...(source.tabLocalIdentifier ? { tabLocalIdentifier: source.tabLocalIdentifier } : {}),
151
- };
152
- if (isAllTimeDashboardDateFilter(filter)) {
153
- return { type: "allTime", ...shared };
154
- }
155
- return {
156
- type,
157
- granularity,
158
- from,
159
- to,
160
- ...(boundedFilter ? { boundedFilter } : {}),
161
- ...shared,
162
- };
163
- }
164
- function upsertDateFilterOnTab(targetTab, payload, isSource) {
117
+ function upsertDateFilterOnTab(targetTab, payload) {
165
118
  if (!targetTab.filterContext) {
166
- if (!isSource) {
167
- return;
168
- }
169
119
  targetTab.filterContext = { ...filterContextInitialState };
170
120
  }
171
121
  const filterContextDefinition = payload.isWorkingSelectionChange
172
122
  ? targetTab.filterContext.workingFilterContextDefinition
173
123
  : targetTab.filterContext.filterContextDefinition;
174
- if (!isSource && !filterContextDefinition?.filters) {
175
- return;
176
- }
177
124
  invariant(filterContextDefinition?.filters, "Attempt to edit uninitialized filter context");
178
125
  const dateDataSet = payload.dataSet;
179
126
  let existingFilterIndex = -1;
@@ -183,9 +130,6 @@ function upsertDateFilterOnTab(targetTab, payload, isSource) {
183
130
  else {
184
131
  existingFilterIndex = filterContextDefinition.filters.findIndex((item) => isDashboardCommonDateFilter(item));
185
132
  }
186
- if (!isSource && existingFilterIndex < 0 && dateDataSet) {
187
- return;
188
- }
189
133
  if (payload.isWorkingSelectionChange && payload.type === "allTime") {
190
134
  // we need to allways set working filter to distinguish between "not changed" and "all time" filter
191
135
  if (existingFilterIndex >= 0) {
@@ -207,15 +151,9 @@ function upsertDateFilterOnTab(targetTab, payload, isSource) {
207
151
  }
208
152
  }
209
153
  else {
210
- const existing = filterContextDefinition.filters[existingFilterIndex];
211
- const preservedLocalIdentifier = isSource
212
- ? payload.localIdentifier
213
- : isDashboardDateFilter(existing)
214
- ? existing.dateFilter.localIdentifier
215
- : undefined;
216
154
  if (payload.emptyValueHandling) {
217
155
  // Preserve all-time common DF when it carries additional config (e.g. emptyValueHandling).
218
- filterContextDefinition.filters[existingFilterIndex] = newAllTimeDashboardDateFilter(undefined, preservedLocalIdentifier, payload.emptyValueHandling);
156
+ filterContextDefinition.filters[existingFilterIndex] = newAllTimeDashboardDateFilter(undefined, payload.localIdentifier, payload.emptyValueHandling);
219
157
  }
220
158
  else {
221
159
  // if allTime common DF remove the date filter altogether
@@ -236,7 +174,7 @@ function upsertDateFilterOnTab(targetTab, payload, isSource) {
236
174
  dateFilter.dateFilter.granularity = granularity;
237
175
  dateFilter.dateFilter.from = from;
238
176
  dateFilter.dateFilter.to = to;
239
- if (localIdentifier && isSource) {
177
+ if (localIdentifier) {
240
178
  dateFilter.dateFilter.localIdentifier = localIdentifier;
241
179
  }
242
180
  if (boundedFilter) {
@@ -253,7 +191,7 @@ function upsertDateFilterOnTab(targetTab, payload, isSource) {
253
191
  }
254
192
  }
255
193
  }
256
- else if (isSource || !dateDataSet) {
194
+ else {
257
195
  const { type, granularity, from, to, dataSet, localIdentifier, boundedFilter, emptyValueHandling } = payload;
258
196
  filterContextDefinition.filters.unshift({
259
197
  dateFilter: {
@@ -270,69 +208,22 @@ function upsertDateFilterOnTab(targetTab, payload, isSource) {
270
208
  }
271
209
  }
272
210
  const updateAttributeFilterSelection = (state, action) => {
273
- const { tabLocalIdentifier, enablePersistentFiltersAcrossTabs, isWorkingSelectionChange, crossFilteringLocalIdsByTab, } = action.payload;
274
- const tabs = getTabsToMutate(state, tabLocalIdentifier, enablePersistentFiltersAcrossTabs, isWorkingSelectionChange);
275
- const source = tabs[0];
276
- if (!source) {
277
- return;
278
- }
279
- const sourceFilter = findAppliedFilterByLocalId(source, action.payload.filterLocalId);
280
- updateAttributeFilterSelectionOnTab(source, action.payload, action.payload.filterLocalId, true);
281
- if (tabs.length === 1 ||
282
- !sourceFilter ||
283
- !isDashboardAttributeFilter(sourceFilter) ||
284
- isCrossFilteringVirtualFilter(source, action.payload.filterLocalId, crossFilteringLocalIdsByTab)) {
211
+ const tab = getTabOrActive(state, action.payload.tabLocalIdentifier);
212
+ if (!tab) {
285
213
  return;
286
214
  }
287
- for (const tab of tabs.slice(1)) {
288
- const match = findCounterpartFilter(source, sourceFilter, tab, state.attributesWithReferences, {
289
- allowListToText: false,
290
- crossFilteringLocalIdsByTab,
291
- });
292
- if (!match || !isDashboardAttributeFilter(match)) {
293
- continue;
294
- }
295
- const targetLocalId = match.attributeFilter.localIdentifier;
296
- if (!targetLocalId) {
297
- continue;
298
- }
299
- const original = action.payload.restoreTargetOriginal ? findOriginalFilter(tab, match) : undefined;
300
- if (action.payload.restoreTargetOriginal && !isDashboardAttributeFilter(original)) {
301
- continue;
302
- }
303
- updateAttributeFilterSelectionOnTab(tab, {
304
- ...action.payload,
305
- filterLocalId: targetLocalId,
306
- ...(isDashboardAttributeFilter(original)
307
- ? {
308
- elements: original.attributeFilter.attributeElements,
309
- negativeSelection: original.attributeFilter.negativeSelection,
310
- }
311
- : {}),
312
- enableImmediateAttributeFilterDisplayAsLabelMigration: false,
313
- isResultOfMigration: false,
314
- }, targetLocalId, false);
315
- }
215
+ updateAttributeFilterSelectionOnTab(tab, action.payload);
316
216
  };
317
- function updateAttributeFilterSelectionOnTab(targetTab, payload, filterLocalId, isSource) {
217
+ function updateAttributeFilterSelectionOnTab(targetTab, payload) {
318
218
  if (!targetTab.filterContext) {
319
- if (!isSource) {
320
- return;
321
- }
322
219
  targetTab.filterContext = { ...filterContextInitialState };
323
220
  }
324
- const { elements, negativeSelection, isWorkingSelectionChange, enableImmediateAttributeFilterDisplayAsLabelMigration, isResultOfMigration, isSelectionInvalid, } = payload;
221
+ const { filterLocalId, elements, negativeSelection, isWorkingSelectionChange, enableImmediateAttributeFilterDisplayAsLabelMigration, isResultOfMigration, isSelectionInvalid, } = payload;
325
222
  const filterContextDefinition = isWorkingSelectionChange
326
223
  ? targetTab.filterContext.workingFilterContextDefinition
327
224
  : targetTab.filterContext.filterContextDefinition;
328
- if (!isSource && !filterContextDefinition?.filters) {
329
- return;
330
- }
331
225
  invariant(filterContextDefinition?.filters, "Attempt to edit uninitialized filter context");
332
226
  const existingFilterIndex = filterContextDefinition.filters.findIndex((item) => isDashboardAttributeFilter(item) && item.attributeFilter.localIdentifier === filterLocalId);
333
- if (!isSource && existingFilterIndex < 0) {
334
- return;
335
- }
336
227
  invariant(existingFilterIndex >= 0 || isWorkingSelectionChange, "Attempt to update non-existing filter");
337
228
  if (isWorkingSelectionChange && existingFilterIndex >= 0) {
338
229
  filterContextDefinition.filters[existingFilterIndex] = {
@@ -393,60 +284,23 @@ function findAppliedFilterByLocalId(tab, localIdentifier) {
393
284
  return tab.filterContext?.filterContextDefinition?.filters.find((item) => dashboardFilterLocalIdentifier(item) === localIdentifier);
394
285
  }
395
286
  const replaceAttributeFilterItem = (state, action) => {
396
- const { tabLocalIdentifier, enablePersistentFiltersAcrossTabs, isWorkingSelectionChange, crossFilteringLocalIdsByTab, } = action.payload;
397
- const tabs = getTabsToMutate(state, tabLocalIdentifier, enablePersistentFiltersAcrossTabs, isWorkingSelectionChange);
398
- const source = tabs[0];
399
- if (!source) {
400
- return;
401
- }
402
- const sourceFilter = findAppliedFilterByLocalId(source, action.payload.filterLocalId);
403
- replaceAttributeFilterItemOnTab(source, action.payload, action.payload.filter, true);
404
- if (tabs.length === 1 ||
405
- !sourceFilter ||
406
- !isDashboardAttributeFilterItem(sourceFilter) ||
407
- isCrossFilteringVirtualFilter(source, action.payload.filterLocalId, crossFilteringLocalIdsByTab)) {
287
+ const tab = getTabOrActive(state, action.payload.tabLocalIdentifier);
288
+ if (!tab) {
408
289
  return;
409
290
  }
410
- for (const tab of tabs.slice(1)) {
411
- const match = findCounterpartFilter(source, sourceFilter, tab, state.attributesWithReferences, {
412
- allowListToText: true,
413
- crossFilteringLocalIdsByTab,
414
- });
415
- if (!match || !isDashboardAttributeFilterItem(match)) {
416
- continue;
417
- }
418
- const targetLocalId = dashboardAttributeFilterItemLocalIdentifier(match);
419
- if (!targetLocalId) {
420
- continue;
421
- }
422
- const original = action.payload.restoreTargetOriginal ? findOriginalFilter(tab, match) : undefined;
423
- if (action.payload.restoreTargetOriginal && !isDashboardAttributeFilterItem(original)) {
424
- continue;
425
- }
426
- const replacement = isDashboardAttributeFilterItem(original) ? original : action.payload.filter;
427
- replaceAttributeFilterItemOnTab(tab, { ...action.payload, filterLocalId: targetLocalId }, retargetAttributeFilterItem(replacement, targetLocalId), false);
428
- }
291
+ replaceAttributeFilterItemOnTab(tab, action.payload);
429
292
  };
430
- function replaceAttributeFilterItemOnTab(targetTab, payload, filter, isSource) {
293
+ function replaceAttributeFilterItemOnTab(targetTab, payload) {
431
294
  if (!targetTab.filterContext) {
432
- if (!isSource) {
433
- return;
434
- }
435
295
  targetTab.filterContext = { ...filterContextInitialState };
436
296
  }
437
- const { filterLocalId, isWorkingSelectionChange, isSelectionInvalid } = payload;
297
+ const { filterLocalId, filter, isWorkingSelectionChange, isSelectionInvalid } = payload;
438
298
  const filterContextDefinition = isWorkingSelectionChange
439
299
  ? targetTab.filterContext.workingFilterContextDefinition
440
300
  : targetTab.filterContext.filterContextDefinition;
441
- if (!isSource && !filterContextDefinition?.filters) {
442
- return;
443
- }
444
301
  invariant(filterContextDefinition?.filters, "Attempt to edit uninitialized filter context");
445
302
  const existingFilterIndex = filterContextDefinition.filters.findIndex((item) => isDashboardAttributeFilterItem(item) &&
446
303
  dashboardAttributeFilterItemLocalIdentifier(item) === filterLocalId);
447
- if (!isSource && existingFilterIndex < 0) {
448
- return;
449
- }
450
304
  // Preserve parent filter relationships from the existing filter when replacing.
451
305
  // The replacement filter typically only carries selection data, not dependency configuration.
452
306
  const replacementFilter = existingFilterIndex >= 0
@@ -480,17 +334,14 @@ function replaceAttributeFilterItemOnTab(targetTab, payload, filter, isSource) {
480
334
  }
481
335
  }
482
336
  const addAttributeFilter = (state, action) => {
483
- const activeTab = getActiveTab(state);
484
- if (!activeTab) {
337
+ const target = getEditableFilterContext(state, action.payload.tabLocalIdentifier);
338
+ if (!target) {
485
339
  return;
486
340
  }
487
- if (!activeTab.filterContext) {
488
- activeTab.filterContext = { ...filterContextInitialState };
489
- }
490
- invariant(activeTab.filterContext.filterContextDefinition, "Attempt to edit uninitialized filter context");
491
341
  const { displayForm, index, initialIsNegativeSelection, initialSelection, parentFilters, selectionMode, localIdentifier, title, } = action.payload;
342
+ const { definition } = target;
492
343
  // Filters are indexed just for attribute filters, if DateFilter is present should be always first item
493
- const isDateFilterPresent = activeTab.filterContext.filterContextDefinition.filters.findIndex(isDashboardDateFilter) >= 0;
344
+ const isDateFilterPresent = definition.filters.findIndex(isDashboardDateFilter) >= 0;
494
345
  const hasSelection = initialSelection && !attributeElementsIsEmpty(initialSelection);
495
346
  const isNegative = selectionMode !== "single" && (initialIsNegativeSelection || !hasSelection);
496
347
  // If DateFilter is present we have to move index by 1 because index of filter is calculated just for AttributeFilers array
@@ -500,117 +351,152 @@ const addAttributeFilter = (state, action) => {
500
351
  attributeElements: initialSelection ?? { uris: [] },
501
352
  displayForm,
502
353
  negativeSelection: isNegative,
503
- localIdentifier: localIdentifier ??
504
- generateFilterLocalIdentifier(displayForm, Math.max(0, attributeFilterIndex)),
354
+ localIdentifier: resolveAttributeFilterLocalIdentifier(definition, displayForm, attributeFilterIndex, localIdentifier),
505
355
  filterElementsBy: parentFilters ? [...parentFilters] : undefined,
506
356
  ...(selectionMode === undefined ? {} : { selectionMode }),
507
357
  title,
508
358
  },
509
359
  };
510
360
  if (index === -1) {
511
- activeTab.filterContext.filterContextDefinition.filters.push(filter);
361
+ definition.filters.push(filter);
512
362
  }
513
363
  else {
514
- activeTab.filterContext.filterContextDefinition.filters.splice(attributeFilterIndex, 0, filter);
364
+ definition.filters.splice(attributeFilterIndex, 0, filter);
515
365
  }
516
366
  };
517
367
  const addTextAttributeFilter = (state, action) => {
518
- const activeTab = getActiveTab(state);
519
- if (!activeTab) {
368
+ const target = getEditableFilterContext(state, action.payload.tabLocalIdentifier);
369
+ if (!target) {
520
370
  return;
521
371
  }
522
- if (!activeTab.filterContext) {
523
- activeTab.filterContext = { ...filterContextInitialState };
524
- }
525
- invariant(activeTab.filterContext.filterContextDefinition, "Attempt to edit uninitialized filter context");
526
372
  const { filter, index } = action.payload;
373
+ const { definition } = target;
527
374
  // Filters are indexed just for attribute filters, if DateFilter is present should be always first item
528
- const isDateFilterPresent = activeTab.filterContext.filterContextDefinition.filters.findIndex(isDashboardDateFilter) >= 0;
375
+ const isDateFilterPresent = definition.filters.findIndex(isDashboardDateFilter) >= 0;
529
376
  const attributeFilterIndex = isDateFilterPresent ? index + 1 : index;
530
- const generatedLocalIdentifierIndex = Math.max(0, attributeFilterIndex);
531
- const filterWithLocalIdentifier = isDashboardArbitraryAttributeFilter(filter)
532
- ? {
377
+ const filterWithLocalIdentifier = withAttributeFilterLocalIdentifier(filter, resolveAttributeFilterLocalIdentifier(definition, dashboardAttributeFilterItemDisplayForm(filter), attributeFilterIndex, dashboardAttributeFilterItemLocalIdentifier(filter)));
378
+ if (!filterWithLocalIdentifier) {
379
+ return;
380
+ }
381
+ if (index === -1) {
382
+ definition.filters.push(filterWithLocalIdentifier);
383
+ }
384
+ else {
385
+ definition.filters.splice(attributeFilterIndex, 0, filterWithLocalIdentifier);
386
+ }
387
+ };
388
+ function withAttributeFilterLocalIdentifier(filter, localIdentifier) {
389
+ if (isDashboardArbitraryAttributeFilter(filter)) {
390
+ return {
533
391
  arbitraryAttributeFilter: {
534
392
  ...filter.arbitraryAttributeFilter,
535
- localIdentifier: filter.arbitraryAttributeFilter.localIdentifier ??
536
- generateFilterLocalIdentifier(filter.arbitraryAttributeFilter.displayForm, generatedLocalIdentifierIndex),
393
+ localIdentifier,
394
+ },
395
+ };
396
+ }
397
+ if (isDashboardMatchAttributeFilter(filter)) {
398
+ return {
399
+ matchAttributeFilter: {
400
+ ...filter.matchAttributeFilter,
401
+ localIdentifier,
537
402
  },
403
+ };
404
+ }
405
+ return undefined;
406
+ }
407
+ /**
408
+ * Keeps `preferred` unless another filter on the tab already uses it, otherwise generates
409
+ * the first free identifier. A filter mirrored from another tab can collide with a local one.
410
+ */
411
+ function resolveAttributeFilterLocalIdentifier(definition, displayForm, index, preferred) {
412
+ return resolveFilterLocalIdentifier(definition, (candidateIndex) => generateFilterLocalIdentifier(displayForm, candidateIndex), index, preferred);
413
+ }
414
+ function resolveFilterLocalIdentifier(definition, generate, index, preferred) {
415
+ const used = new Set();
416
+ for (const item of definition.filters) {
417
+ const localIdentifier = dashboardFilterLocalIdentifier(item);
418
+ if (localIdentifier) {
419
+ used.add(localIdentifier);
538
420
  }
539
- : isDashboardMatchAttributeFilter(filter)
540
- ? {
541
- matchAttributeFilter: {
542
- ...filter.matchAttributeFilter,
543
- localIdentifier: filter.matchAttributeFilter.localIdentifier ??
544
- generateFilterLocalIdentifier(filter.matchAttributeFilter.displayForm, generatedLocalIdentifierIndex),
545
- },
546
- }
547
- : filter;
548
- if (index === -1) {
549
- activeTab.filterContext.filterContextDefinition.filters.push(filterWithLocalIdentifier);
550
421
  }
551
- else {
552
- activeTab.filterContext.filterContextDefinition.filters.splice(attributeFilterIndex, 0, filterWithLocalIdentifier);
422
+ if (preferred && !used.has(preferred)) {
423
+ return preferred;
553
424
  }
554
- };
425
+ let candidateIndex = Math.max(0, index);
426
+ let localIdentifier = generate(candidateIndex);
427
+ while (used.has(localIdentifier)) {
428
+ candidateIndex += 1;
429
+ localIdentifier = generate(candidateIndex);
430
+ }
431
+ return localIdentifier;
432
+ }
555
433
  const removeAttributeFilter = (state, action) => {
556
- const activeTab = getActiveTab(state);
557
- if (!activeTab) {
434
+ const target = getEditableFilterContext(state, action.payload.tabLocalIdentifier);
435
+ if (!target) {
558
436
  return;
559
437
  }
560
- if (!activeTab.filterContext) {
561
- activeTab.filterContext = { ...filterContextInitialState };
562
- }
563
- invariant(activeTab.filterContext.filterContextDefinition, "Attempt to edit uninitialized filter context");
564
438
  const { filterLocalId } = action.payload;
565
- const newFilters = activeTab.filterContext.filterContextDefinition.filters.filter((item) => isDashboardDateFilter(item) ||
566
- !isDashboardAttributeFilterItem(item) ||
567
- dashboardAttributeFilterItemLocalIdentifier(item) !== filterLocalId);
568
- activeTab.filterContext.filterContextDefinition = {
569
- ...activeTab.filterContext.filterContextDefinition,
570
- filters: newFilters,
439
+ const { filterContext, definition } = target;
440
+ filterContext.filterContextDefinition = {
441
+ ...definition,
442
+ filters: definition.filters.filter((item) => isDashboardDateFilter(item) ||
443
+ !isDashboardAttributeFilterItem(item) ||
444
+ dashboardAttributeFilterItemLocalIdentifier(item) !== filterLocalId),
571
445
  };
446
+ removeAttributeFilterParentReferences(filterContext.filterContextDefinition, filterLocalId);
572
447
  };
448
+ /**
449
+ * Drops parent references to a removed filter, including children that exist only on this tab.
450
+ */
451
+ function removeAttributeFilterParentReferences(definition, removedLocalId) {
452
+ for (const item of definition.filters) {
453
+ if (isDashboardAttributeFilter(item) && item.attributeFilter.filterElementsBy) {
454
+ const remaining = item.attributeFilter.filterElementsBy.filter((parent) => parent.filterLocalIdentifier !== removedLocalId);
455
+ if (remaining.length !== item.attributeFilter.filterElementsBy.length) {
456
+ item.attributeFilter.filterElementsBy = remaining;
457
+ }
458
+ }
459
+ else if (isDashboardArbitraryAttributeFilter(item) &&
460
+ item.arbitraryAttributeFilter.filterElementsBy) {
461
+ const remaining = item.arbitraryAttributeFilter.filterElementsBy.filter((parent) => parent.filterLocalIdentifier !== removedLocalId);
462
+ if (remaining.length !== item.arbitraryAttributeFilter.filterElementsBy.length) {
463
+ item.arbitraryAttributeFilter.filterElementsBy = remaining;
464
+ }
465
+ }
466
+ }
467
+ }
573
468
  const moveAttributeFilter = (state, action) => {
574
- const activeTab = getActiveTab(state);
575
- if (!activeTab) {
469
+ const target = getEditableFilterContext(state, action.payload.tabLocalIdentifier);
470
+ if (!target) {
576
471
  return;
577
472
  }
578
- if (!activeTab.filterContext) {
579
- activeTab.filterContext = { ...filterContextInitialState };
580
- }
581
- invariant(activeTab.filterContext.filterContextDefinition, "Attempt to edit uninitialized filter context");
582
473
  const { filterLocalId, index } = action.payload;
583
- const currentFilterIndex = activeTab.filterContext.filterContextDefinition.filters.findIndex((item) => isDashboardAttributeFilterItem(item) &&
474
+ const filters = target.definition.filters;
475
+ const currentFilterIndex = filters.findIndex((item) => isDashboardAttributeFilterItem(item) &&
584
476
  dashboardAttributeFilterItemLocalIdentifier(item) === filterLocalId);
585
477
  invariant(currentFilterIndex >= 0, "Attempt to move non-existing filter");
586
- const filter = activeTab.filterContext.filterContextDefinition.filters[currentFilterIndex];
587
- activeTab.filterContext.filterContextDefinition.filters.splice(currentFilterIndex, 1);
478
+ const filter = filters[currentFilterIndex];
479
+ filters.splice(currentFilterIndex, 1);
588
480
  // Filters are indexed just for attribute filters, if DateFilter is present should be always first item
589
- const isDateFilterPresent = activeTab.filterContext.filterContextDefinition.filters.findIndex(isDashboardDateFilter) >= 0;
481
+ const isDateFilterPresent = filters.findIndex(isDashboardDateFilter) >= 0;
590
482
  if (index === -1) {
591
- activeTab.filterContext.filterContextDefinition.filters.push(filter);
483
+ filters.push(filter);
592
484
  }
593
485
  else {
594
486
  // If DateFilter is present we have to move index by 1 because index of filter is calculated just for AttributeFilers array
595
487
  const attributeFilterIndex = isDateFilterPresent ? index + 1 : index;
596
- activeTab.filterContext.filterContextDefinition.filters.splice(attributeFilterIndex, 0, filter);
488
+ filters.splice(attributeFilterIndex, 0, filter);
597
489
  }
598
490
  };
599
491
  const setAttributeFilterParents = (state, action) => {
600
- const activeTab = getActiveTab(state);
601
- if (!activeTab) {
492
+ const target = getEditableFilterContext(state, action.payload.tabLocalIdentifier);
493
+ if (!target) {
602
494
  return;
603
495
  }
604
- if (!activeTab.filterContext) {
605
- activeTab.filterContext = { ...filterContextInitialState };
606
- }
607
- invariant(activeTab.filterContext.filterContextDefinition, "Attempt to edit uninitialized filter context");
608
496
  const { filterLocalId, parentFilters } = action.payload;
609
- const currentFilterIndex = activeTab.filterContext.filterContextDefinition.filters.findIndex((item) => isDashboardAttributeFilterItem(item) &&
610
- dashboardAttributeFilterItemLocalIdentifier(item) === filterLocalId);
611
- invariant(currentFilterIndex >= 0, "Attempt to set parent of a non-existing filter");
497
+ const filter = findAttributeFilterItem(target.definition, filterLocalId);
498
+ invariant(filter, "Attempt to set parent of a non-existing filter");
612
499
  // silently ignore when targeting match filter, will have no effect
613
- const filter = activeTab.filterContext.filterContextDefinition.filters[currentFilterIndex];
614
500
  if (isDashboardAttributeFilter(filter)) {
615
501
  filter.attributeFilter.filterElementsBy = [...parentFilters];
616
502
  }
@@ -619,19 +505,13 @@ const setAttributeFilterParents = (state, action) => {
619
505
  }
620
506
  };
621
507
  const setAttributeFilterDependentDateFilters = (state, action) => {
622
- const activeTab = getActiveTab(state);
623
- if (!activeTab) {
508
+ const target = getEditableFilterContext(state, action.payload.tabLocalIdentifier);
509
+ if (!target) {
624
510
  return;
625
511
  }
626
- if (!activeTab.filterContext) {
627
- activeTab.filterContext = { ...filterContextInitialState };
628
- }
629
- invariant(activeTab.filterContext.filterContextDefinition, "Attempt to edit uninitialized filter context");
630
512
  const { filterLocalId, dependentDateFilters } = action.payload;
631
- const currentFilterIndex = activeTab.filterContext.filterContextDefinition.filters.findIndex((item) => isDashboardAttributeFilterItem(item) &&
632
- dashboardAttributeFilterItemLocalIdentifier(item) === filterLocalId);
633
- invariant(currentFilterIndex >= 0, "Attempt to set dependent date filter of a non-existing filter");
634
- const filter = activeTab.filterContext.filterContextDefinition.filters[currentFilterIndex];
513
+ const filter = findAttributeFilterItem(target.definition, filterLocalId);
514
+ invariant(filter, "Attempt to set dependent date filter of a non-existing filter");
635
515
  if (isDashboardAttributeFilter(filter)) {
636
516
  filter.attributeFilter.filterElementsByDate = [...dependentDateFilters];
637
517
  }
@@ -640,64 +520,43 @@ const setAttributeFilterDependentDateFilters = (state, action) => {
640
520
  }
641
521
  // Match filters do not support filterElementsByDate
642
522
  };
523
+ function findAttributeFilterItem(definition, localIdentifier) {
524
+ return definition.filters.find((item) => isDashboardAttributeFilterItem(item) &&
525
+ dashboardAttributeFilterItemLocalIdentifier(item) === localIdentifier);
526
+ }
643
527
  const clearAttributeFiltersSelection = (state, action) => {
644
- const { tabLocalIdentifier, enablePersistentFiltersAcrossTabs, filterLocalIds, crossFilteringLocalIdsByTab, } = action.payload;
645
- const tabs = getTabsToMutate(state, tabLocalIdentifier, enablePersistentFiltersAcrossTabs);
646
- const source = tabs[0];
647
- if (!source) {
528
+ const { tabLocalIdentifier, filterLocalIds, restoreOriginal } = action.payload;
529
+ const tab = getTabOrActive(state, tabLocalIdentifier);
530
+ if (!tab) {
648
531
  return;
649
532
  }
650
- if (!source.filterContext) {
651
- source.filterContext = { ...filterContextInitialState };
533
+ if (!tab.filterContext) {
534
+ tab.filterContext = { ...filterContextInitialState };
652
535
  }
653
- const sourceFilters = filterLocalIds.map((filterLocalId) => ({
654
- filterLocalId,
655
- filter: findAppliedFilterByLocalId(source, filterLocalId),
656
- }));
657
- filterLocalIds.forEach((filterLocalId) => {
658
- clearAttributeFilterSelectionOnTab(source, filterLocalId, true);
659
- });
660
- for (const tab of tabs.slice(1)) {
661
- for (const { filterLocalId, filter } of sourceFilters) {
662
- if (!filter ||
663
- !isDashboardAttributeFilter(filter) ||
664
- isCrossFilteringVirtualFilter(source, filterLocalId, crossFilteringLocalIdsByTab)) {
665
- continue;
666
- }
667
- const match = findCounterpartFilter(source, filter, tab, state.attributesWithReferences, {
668
- allowListToText: false,
669
- crossFilteringLocalIdsByTab,
670
- });
671
- if (!match || !isDashboardAttributeFilter(match) || !match.attributeFilter.localIdentifier) {
672
- continue;
673
- }
674
- const targetLocalId = match.attributeFilter.localIdentifier;
675
- if (action.payload.restoreTargetOriginal) {
676
- const original = findOriginalFilter(tab, match);
677
- if (!isDashboardAttributeFilter(original)) {
678
- continue;
679
- }
680
- updateAttributeFilterSelectionOnTab(tab, {
681
- filterLocalId: targetLocalId,
682
- elements: original.attributeFilter.attributeElements,
683
- negativeSelection: original.attributeFilter.negativeSelection,
684
- }, targetLocalId, false);
685
- continue;
686
- }
687
- clearAttributeFilterSelectionOnTab(tab, targetLocalId, false);
536
+ for (const filterLocalId of filterLocalIds) {
537
+ if (restoreOriginal) {
538
+ restoreAttributeFilterSelectionOnTab(tab, filterLocalId);
539
+ }
540
+ else {
541
+ clearAttributeFilterSelectionOnTab(tab, filterLocalId);
688
542
  }
689
543
  }
690
544
  };
691
- function clearAttributeFilterSelectionOnTab(tab, filterLocalId, isSource) {
692
- const filters = tab.filterContext?.filterContextDefinition?.filters;
693
- if (!isSource && !filters) {
545
+ function restoreAttributeFilterSelectionOnTab(tab, filterLocalId) {
546
+ const filter = findAppliedFilterByLocalId(tab, filterLocalId);
547
+ const original = filter ? findOriginalFilter(tab, filter) : undefined;
548
+ if (!isDashboardAttributeFilter(original)) {
694
549
  return;
695
550
  }
551
+ updateAttributeFilterSelectionOnTab(tab, {
552
+ filterLocalId,
553
+ elements: original.attributeFilter.attributeElements,
554
+ negativeSelection: original.attributeFilter.negativeSelection,
555
+ });
556
+ }
557
+ function clearAttributeFilterSelectionOnTab(tab, filterLocalId) {
696
558
  invariant(tab.filterContext?.filterContextDefinition, "Attempt to edit uninitialized filter context");
697
559
  const currentFilterIndex = tab.filterContext.filterContextDefinition.filters.findIndex((item) => isDashboardAttributeFilter(item) && item.attributeFilter.localIdentifier === filterLocalId);
698
- if (!isSource && currentFilterIndex < 0) {
699
- return;
700
- }
701
560
  invariant(currentFilterIndex >= 0, "Attempt to clear selection of a non-existing filter");
702
561
  const currentFilter = tab.filterContext.filterContextDefinition.filters[currentFilterIndex];
703
562
  currentFilter.attributeFilter.negativeSelection =
@@ -710,17 +569,15 @@ function clearAttributeFilterSelectionOnTab(tab, filterLocalId, isSource) {
710
569
  * Changes the display form for the filter given by its local identifier.
711
570
  */
712
571
  const changeAttributeDisplayForm = (state, action) => {
713
- const targetTab = getTabOrActive(state, action.payload.tabLocalIdentifier);
714
- if (!targetTab) {
572
+ const target = getTabFilterContext(state, action.payload.tabLocalIdentifier);
573
+ if (!target) {
715
574
  return;
716
575
  }
717
- if (!targetTab.filterContext) {
718
- targetTab.filterContext = { ...filterContextInitialState };
719
- }
720
576
  const { filterLocalId, displayForm, isWorkingSelectionChange, enableImmediateAttributeFilterDisplayAsLabelMigration, isResultOfMigration, } = action.payload;
577
+ const { filterContext } = target;
721
578
  const filterContextDefinition = isWorkingSelectionChange
722
- ? targetTab.filterContext.workingFilterContextDefinition
723
- : targetTab.filterContext.filterContextDefinition;
579
+ ? filterContext.workingFilterContextDefinition
580
+ : filterContext.filterContextDefinition;
724
581
  invariant(filterContextDefinition?.filters, "Attempt to edit uninitialized filter context");
725
582
  const currentFilterIndex = filterContextDefinition.filters.findIndex((item) => isDashboardAttributeFilter(item) && item.attributeFilter.localIdentifier === filterLocalId);
726
583
  invariant(currentFilterIndex >= 0 || isWorkingSelectionChange, "Attempt to set parent of a non-existing filter");
@@ -738,7 +595,7 @@ const changeAttributeDisplayForm = (state, action) => {
738
595
  currentFilter.attributeFilter.displayForm = { ...displayForm };
739
596
  // update original filters to not show "reset filters" button, that will revert filter to wrong state
740
597
  if (enableImmediateAttributeFilterDisplayAsLabelMigration && isResultOfMigration) {
741
- const originalFilter = targetTab.filterContext.originalFilterContextDefinition?.filters.find((item) => isDashboardAttributeFilter(item) && item.attributeFilter.localIdentifier === filterLocalId);
598
+ const originalFilter = filterContext.originalFilterContextDefinition?.filters.find((item) => isDashboardAttributeFilter(item) && item.attributeFilter.localIdentifier === filterLocalId);
742
599
  if (isDashboardAttributeFilter(originalFilter)) {
743
600
  originalFilter.attributeFilter.displayForm = { ...displayForm };
744
601
  }
@@ -751,21 +608,12 @@ const changeAttributeDisplayForm = (state, action) => {
751
608
  */
752
609
  const changeTextFilterDisplayForm = (state, action) => {
753
610
  const targetTab = getTabOrActive(state, action.payload.tabLocalIdentifier);
754
- if (!targetTab?.filterContext) {
755
- return;
756
- }
757
- const { filterLocalId, displayForm } = action.payload;
758
- const filterContextDefinition = targetTab.filterContext.filterContextDefinition;
611
+ const filterContextDefinition = targetTab?.filterContext?.filterContextDefinition;
759
612
  if (!filterContextDefinition?.filters) {
760
613
  return;
761
614
  }
762
- const currentFilterIndex = filterContextDefinition.filters.findIndex((item) => isDashboardAttributeFilterItem(item) &&
763
- !isDashboardAttributeFilter(item) &&
764
- dashboardAttributeFilterItemLocalIdentifier(item) === filterLocalId);
765
- if (currentFilterIndex < 0) {
766
- return;
767
- }
768
- const filter = filterContextDefinition.filters[currentFilterIndex];
615
+ const { filterLocalId, displayForm } = action.payload;
616
+ const filter = findAttributeFilterItem(filterContextDefinition, filterLocalId);
769
617
  if (isDashboardArbitraryAttributeFilter(filter)) {
770
618
  filter.arbitraryAttributeFilter.displayForm = { ...displayForm };
771
619
  }
@@ -777,17 +625,12 @@ const changeTextFilterDisplayForm = (state, action) => {
777
625
  * Changes the title for the filter given by its local identifier.
778
626
  */
779
627
  const changeAttributeTitle = (state, action) => {
780
- const activeTab = getActiveTab(state);
781
- if (!activeTab) {
628
+ const target = getEditableFilterContext(state, action.payload.tabLocalIdentifier);
629
+ if (!target) {
782
630
  return;
783
631
  }
784
- if (!activeTab.filterContext) {
785
- activeTab.filterContext = { ...filterContextInitialState };
786
- }
787
- invariant(activeTab.filterContext.filterContextDefinition, "Attempt to edit uninitialized filter context");
788
632
  const { filterLocalId, title } = action.payload;
789
- const findFilter = activeTab.filterContext.filterContextDefinition.filters.find((item) => isDashboardAttributeFilterItem(item) &&
790
- dashboardAttributeFilterItemLocalIdentifier(item) === filterLocalId);
633
+ const findFilter = findAttributeFilterItem(target.definition, filterLocalId);
791
634
  invariant(findFilter, "Attempt to change title of a non-existing filter");
792
635
  if (isDashboardAttributeFilter(findFilter)) {
793
636
  findFilter.attributeFilter.title = title;
@@ -803,17 +646,12 @@ const changeAttributeTitle = (state, action) => {
803
646
  * Changes the selection mode for the filter given by its local identifier.
804
647
  */
805
648
  const changeSelectionMode = (state, action) => {
806
- const activeTab = getActiveTab(state);
807
- if (!activeTab) {
649
+ const target = getEditableFilterContext(state, action.payload.tabLocalIdentifier);
650
+ if (!target) {
808
651
  return;
809
652
  }
810
- if (!activeTab.filterContext) {
811
- activeTab.filterContext = { ...filterContextInitialState };
812
- }
813
- invariant(activeTab.filterContext.filterContextDefinition, "Attempt to edit uninitialized filter context");
814
653
  const { filterLocalId, selectionMode } = action.payload;
815
- const findFilter = activeTab.filterContext.filterContextDefinition.filters.find((item) => isDashboardAttributeFilterItem(item) &&
816
- dashboardAttributeFilterItemLocalIdentifier(item) === filterLocalId);
654
+ const findFilter = findAttributeFilterItem(target.definition, filterLocalId);
817
655
  invariant(findFilter, "Attempt to change selection mode of a non-existing filter");
818
656
  // Text filters (arbitrary, match) do not have selectionMode; no-op for them
819
657
  if (isDashboardAttributeFilter(findFilter)) {
@@ -821,15 +659,12 @@ const changeSelectionMode = (state, action) => {
821
659
  }
822
660
  };
823
661
  const addDateFilter = (state, action) => {
824
- const activeTab = getActiveTab(state);
825
- if (!activeTab) {
662
+ const target = getEditableFilterContext(state, action.payload.tabLocalIdentifier);
663
+ if (!target) {
826
664
  return;
827
665
  }
828
- if (!activeTab.filterContext) {
829
- activeTab.filterContext = { ...filterContextInitialState };
830
- }
831
- invariant(activeTab.filterContext.filterContextDefinition, "Attempt to edit uninitialized filter context");
832
666
  const { index, dateDataset } = action.payload;
667
+ const { definition } = target;
833
668
  const filter = {
834
669
  dateFilter: {
835
670
  dataSet: dateDataset,
@@ -838,73 +673,58 @@ const addDateFilter = (state, action) => {
838
673
  },
839
674
  };
840
675
  // Only draggable filters are indexed, if DateFilter is present should be always first item
841
- const isCommonDateFilterPresent = activeTab.filterContext.filterContextDefinition.filters.findIndex(isDashboardCommonDateFilter) >= 0;
676
+ const isCommonDateFilterPresent = definition.filters.findIndex(isDashboardCommonDateFilter) >= 0;
842
677
  if (index === -1) {
843
- activeTab.filterContext.filterContextDefinition.filters.push(filter);
678
+ definition.filters.push(filter);
844
679
  }
845
680
  else {
846
681
  // If CommonDateFilter is present we have to move index by 1 because index of filter is calculated just for AttributeFilers array
847
682
  const newFilterIndex = isCommonDateFilterPresent ? index + 1 : index;
848
- activeTab.filterContext.filterContextDefinition.filters.splice(newFilterIndex, 0, filter);
683
+ definition.filters.splice(newFilterIndex, 0, filter);
849
684
  }
850
685
  };
851
- //
852
- //
853
- //
854
686
  const addMeasureValueFilter = (state, action) => {
855
- // A new measure value filter has no counterpart yet. Creating one on other tabs would be a
856
- // phantom filter, so the add stays on the source tab even when sync is on.
857
- const activeTab = getTabsToMutate(state)[0];
858
- if (!activeTab) {
687
+ const target = getEditableFilterContext(state, action.payload.tabLocalIdentifier);
688
+ if (!target) {
859
689
  return;
860
690
  }
861
- if (!activeTab.filterContext) {
862
- activeTab.filterContext = { ...filterContextInitialState };
863
- }
864
- invariant(activeTab.filterContext.filterContextDefinition, "Attempt to edit uninitialized filter context");
865
691
  const { index, measure, localIdentifier, title } = action.payload;
692
+ const { definition } = target;
866
693
  const filter = {
867
694
  dashboardMeasureValueFilter: {
868
695
  measure,
869
- localIdentifier: localIdentifier ?? generateMeasureValueFilterLocalIdentifier(measure, Math.max(0, index)),
696
+ localIdentifier: resolveFilterLocalIdentifier(definition, (candidateIndex) => generateMeasureValueFilterLocalIdentifier(measure, candidateIndex), index, localIdentifier),
870
697
  title,
871
698
  },
872
699
  };
873
- const isCommonDateFilterPresent = activeTab.filterContext.filterContextDefinition.filters.findIndex(isDashboardCommonDateFilter) >= 0;
700
+ const isCommonDateFilterPresent = definition.filters.findIndex(isDashboardCommonDateFilter) >= 0;
874
701
  if (index === -1) {
875
- activeTab.filterContext.filterContextDefinition.filters.push(filter);
702
+ definition.filters.push(filter);
876
703
  }
877
704
  else {
878
705
  const newFilterIndex = isCommonDateFilterPresent ? index + 1 : index;
879
- activeTab.filterContext.filterContextDefinition.filters.splice(newFilterIndex, 0, filter);
706
+ definition.filters.splice(newFilterIndex, 0, filter);
880
707
  }
881
708
  };
882
709
  const removeMeasureValueFilter = (state, action) => {
883
- const activeTab = getActiveTab(state);
884
- if (!activeTab) {
710
+ const target = getEditableFilterContext(state, action.payload.tabLocalIdentifier);
711
+ if (!target) {
885
712
  return;
886
713
  }
887
- if (!activeTab.filterContext) {
888
- activeTab.filterContext = { ...filterContextInitialState };
889
- }
890
- invariant(activeTab.filterContext.filterContextDefinition, "Attempt to edit uninitialized filter context");
891
- activeTab.filterContext.filterContextDefinition = {
892
- ...activeTab.filterContext.filterContextDefinition,
893
- filters: activeTab.filterContext.filterContextDefinition.filters.filter((item) => !(isDashboardMeasureValueFilter(item) &&
894
- dashboardFilterLocalIdentifier(item) === action.payload.localIdentifier)),
714
+ const { localIdentifier } = action.payload;
715
+ target.filterContext.filterContextDefinition = {
716
+ ...target.definition,
717
+ filters: target.definition.filters.filter((item) => !(isDashboardMeasureValueFilter(item) &&
718
+ dashboardFilterLocalIdentifier(item) === localIdentifier)),
895
719
  };
896
720
  };
897
721
  const moveMeasureValueFilter = (state, action) => {
898
- const activeTab = getActiveTab(state);
899
- if (!activeTab) {
722
+ const target = getEditableFilterContext(state, action.payload.tabLocalIdentifier);
723
+ if (!target) {
900
724
  return;
901
725
  }
902
- if (!activeTab.filterContext) {
903
- activeTab.filterContext = { ...filterContextInitialState };
904
- }
905
- invariant(activeTab.filterContext.filterContextDefinition, "Attempt to edit uninitialized filter context");
906
726
  const { localIdentifier, index } = action.payload;
907
- const filters = activeTab.filterContext.filterContextDefinition.filters;
727
+ const filters = target.definition.filters;
908
728
  const currentFilterIndex = filters.findIndex((item) => isDashboardMeasureValueFilter(item) && dashboardFilterLocalIdentifier(item) === localIdentifier);
909
729
  invariant(currentFilterIndex >= 0, "Attempt to move non-existing measure value filter");
910
730
  const filter = filters[currentFilterIndex];
@@ -919,61 +739,91 @@ const moveMeasureValueFilter = (state, action) => {
919
739
  }
920
740
  };
921
741
  const removeDateFilter = (state, action) => {
922
- const activeTab = getActiveTab(state);
923
- if (!activeTab) {
742
+ const target = getEditableFilterContext(state, action.payload.tabLocalIdentifier);
743
+ if (!target) {
924
744
  return;
925
745
  }
926
- if (!activeTab.filterContext) {
927
- activeTab.filterContext = { ...filterContextInitialState };
928
- }
929
- invariant(activeTab.filterContext.filterContextDefinition, "Attempt to edit uninitialized filter context");
930
746
  const { dataSet } = action.payload;
931
- const newFilters = activeTab.filterContext.filterContextDefinition.filters.filter((item) => !isDashboardDateFilter(item) || !areObjRefsEqual(item.dateFilter.dataSet, dataSet));
932
- activeTab.filterContext.filterContextDefinition = {
933
- ...activeTab.filterContext.filterContextDefinition,
934
- filters: newFilters,
747
+ const { filterContext, definition } = target;
748
+ const removed = definition.filters.find((item) => isDashboardDateFilterWithDimension(item) && areObjRefsEqual(item.dateFilter.dataSet, dataSet));
749
+ const removedLocalIdentifier = isDashboardDateFilter(removed)
750
+ ? removed.dateFilter.localIdentifier
751
+ : undefined;
752
+ filterContext.filterContextDefinition = {
753
+ ...definition,
754
+ filters: definition.filters.filter((item) => !isDashboardDateFilter(item) || !areObjRefsEqual(item.dateFilter.dataSet, dataSet)),
935
755
  };
756
+ removeDimensionDateFilterDependencies(filterContext.filterContextDefinition, dataSet, removedLocalIdentifier);
936
757
  };
758
+ /**
759
+ * Drops attribute-filter dependencies that point at the removed dimension date filter, including
760
+ * filters that exist only on this tab. Matches both the filter local identifier and the legacy
761
+ * dataset-identifier form.
762
+ */
763
+ function removeDimensionDateFilterDependencies(definition, dataSet, removedLocalIdentifier) {
764
+ const datasetIdentifier = isIdentifierRef(dataSet) ? dataSet.identifier : undefined;
765
+ for (const item of definition.filters) {
766
+ if (isDashboardAttributeFilter(item)) {
767
+ const next = withoutRemovedDateDependency(item.attributeFilter.filterElementsByDate, removedLocalIdentifier, datasetIdentifier);
768
+ if (next !== item.attributeFilter.filterElementsByDate) {
769
+ item.attributeFilter.filterElementsByDate = next;
770
+ }
771
+ }
772
+ else if (isDashboardArbitraryAttributeFilter(item)) {
773
+ const next = withoutRemovedDateDependency(item.arbitraryAttributeFilter.filterElementsByDate, removedLocalIdentifier, datasetIdentifier);
774
+ if (next !== item.arbitraryAttributeFilter.filterElementsByDate) {
775
+ item.arbitraryAttributeFilter.filterElementsByDate = next;
776
+ }
777
+ }
778
+ }
779
+ }
780
+ function withoutRemovedDateDependency(dependencies, removedLocalIdentifier, datasetIdentifier) {
781
+ if (!dependencies?.length) {
782
+ return dependencies;
783
+ }
784
+ const remaining = dependencies.filter((dependency) => {
785
+ if (dependency.isCommonDate) {
786
+ return true;
787
+ }
788
+ const matchesLocalIdentifier = removedLocalIdentifier !== undefined &&
789
+ dependency.filterLocalIdentifier === removedLocalIdentifier;
790
+ const matchesDatasetIdentifier = datasetIdentifier !== undefined && dependency.filterLocalIdentifier === datasetIdentifier;
791
+ return !matchesLocalIdentifier && !matchesDatasetIdentifier;
792
+ });
793
+ return remaining.length === dependencies.length ? dependencies : remaining;
794
+ }
937
795
  const moveDateFilter = (state, action) => {
938
- const activeTab = getActiveTab(state);
939
- if (!activeTab) {
796
+ const target = getEditableFilterContext(state, action.payload.tabLocalIdentifier);
797
+ if (!target) {
940
798
  return;
941
799
  }
942
- if (!activeTab.filterContext) {
943
- activeTab.filterContext = { ...filterContextInitialState };
944
- }
945
- invariant(activeTab.filterContext.filterContextDefinition, "Attempt to edit uninitialized filter context");
946
800
  const { dataSet, index } = action.payload;
947
- const currentFilterIndex = activeTab.filterContext.filterContextDefinition.filters.findIndex((item) => isDashboardDateFilter(item) && areObjRefsEqual(item.dateFilter.dataSet, dataSet));
801
+ const filters = target.definition.filters;
802
+ const currentFilterIndex = filters.findIndex((item) => isDashboardDateFilter(item) && areObjRefsEqual(item.dateFilter.dataSet, dataSet));
948
803
  invariant(currentFilterIndex >= 0, "Attempt to move non-existing filter");
949
- const filter = activeTab.filterContext.filterContextDefinition.filters[currentFilterIndex];
950
- activeTab.filterContext.filterContextDefinition.filters.splice(currentFilterIndex, 1);
804
+ const filter = filters[currentFilterIndex];
805
+ filters.splice(currentFilterIndex, 1);
951
806
  // Filters are indexed just for attribute filters, if DateFilter is present should be always first item
952
- const isCommonDateFilterPresent = activeTab.filterContext.filterContextDefinition.filters.findIndex(isDashboardCommonDateFilter) >= 0;
807
+ const isCommonDateFilterPresent = filters.findIndex(isDashboardCommonDateFilter) >= 0;
953
808
  if (index === -1) {
954
- activeTab.filterContext.filterContextDefinition.filters.push(filter);
809
+ filters.push(filter);
955
810
  }
956
811
  else {
957
812
  // If DateFilter is present we have to move index by 1 because index of filter is calculated just for DraggableFilters array
958
813
  const dateFilterIndex = isCommonDateFilterPresent ? index + 1 : index;
959
- activeTab.filterContext.filterContextDefinition.filters.splice(dateFilterIndex, 0, filter);
814
+ filters.splice(dateFilterIndex, 0, filter);
960
815
  }
961
816
  };
962
817
  /**
963
818
  * Changes the element limiting items for the filter given by its local identifier.
964
819
  */
965
820
  const changeLimitingItems = (state, action) => {
966
- const activeTab = getActiveTab(state);
967
- if (!activeTab) {
821
+ const target = getEditableFilterContext(state, action.payload.tabLocalIdentifier);
822
+ if (!target) {
968
823
  return;
969
824
  }
970
- if (!activeTab.filterContext) {
971
- activeTab.filterContext = { ...filterContextInitialState };
972
- }
973
- invariant(activeTab.filterContext.filterContextDefinition, "Attempt to edit uninitialized filter context");
974
825
  const { filterLocalId, limitingItems } = action.payload;
975
- const findFilter = activeTab.filterContext.filterContextDefinition.filters.find((item) => isDashboardAttributeFilterItem(item) &&
976
- dashboardAttributeFilterItemLocalIdentifier(item) === filterLocalId);
826
+ const findFilter = findAttributeFilterItem(target.definition, filterLocalId);
977
827
  invariant(findFilter, "Attempt to change limiting items of a non-existing filter");
978
828
  if (isDashboardAttributeFilter(findFilter)) {
979
829
  findFilter.attributeFilter.validateElementsBy = limitingItems;
@@ -1012,8 +862,9 @@ export function clearFilterContextWorkingValues(tab) {
1012
862
  tab.filterContext.workingFilterContextDefinition = { filters: [] };
1013
863
  }
1014
864
  const resetWorkingFilterSelection = (state) => {
1015
- for (const tab of getTabsToMutate(state)) {
1016
- clearFilterContextWorkingValues(tab);
865
+ const activeTab = getActiveTab(state);
866
+ if (activeTab) {
867
+ clearFilterContextWorkingValues(activeTab);
1017
868
  }
1018
869
  };
1019
870
  //
@@ -1030,59 +881,24 @@ const setDefaultFilterOverrides = (state, action) => {
1030
881
  activeTab.filterContext.defaultFilterOverrides = action.payload;
1031
882
  };
1032
883
  const changeMeasureValueFilterCondition = (state, action) => {
1033
- const { localIdentifier, isWorkingSelectionChange, enablePersistentFiltersAcrossTabs } = action.payload;
1034
- const tabs = getTabsToMutate(state, undefined, enablePersistentFiltersAcrossTabs, isWorkingSelectionChange);
1035
- const source = tabs[0];
1036
- if (!source) {
1037
- return;
1038
- }
1039
- const sourceFilter = findAppliedFilterByLocalId(source, localIdentifier);
1040
- changeMeasureValueFilterConditionOnTab(source, action.payload, localIdentifier, true);
1041
- if (!sourceFilter || !isDashboardMeasureValueFilter(sourceFilter)) {
884
+ const tab = getTabOrActive(state, action.payload.tabLocalIdentifier);
885
+ if (!tab) {
1042
886
  return;
1043
887
  }
1044
- for (const tab of tabs.slice(1)) {
1045
- const match = findCounterpartFilter(source, sourceFilter, tab, state.attributesWithReferences);
1046
- const targetLocalId = match ? dashboardFilterLocalIdentifier(match) : undefined;
1047
- if (!targetLocalId || !match) {
1048
- continue;
1049
- }
1050
- if (action.payload.restoreTargetOriginal) {
1051
- const original = findOriginalFilter(tab, match);
1052
- if (!isDashboardMeasureValueFilter(original)) {
1053
- continue;
1054
- }
1055
- changeMeasureValueFilterConditionOnTab(tab, {
1056
- ...action.payload,
1057
- localIdentifier: targetLocalId,
1058
- conditions: original.dashboardMeasureValueFilter.conditions,
1059
- }, targetLocalId, false);
1060
- continue;
1061
- }
1062
- changeMeasureValueFilterConditionOnTab(tab, action.payload, targetLocalId, false);
1063
- }
888
+ changeMeasureValueFilterConditionOnTab(tab, action.payload);
1064
889
  };
1065
- function changeMeasureValueFilterConditionOnTab(tab, payload, localIdentifier, isSource) {
890
+ function changeMeasureValueFilterConditionOnTab(tab, payload) {
1066
891
  if (!tab.filterContext) {
1067
- if (!isSource) {
1068
- return;
1069
- }
1070
892
  tab.filterContext = { ...filterContextInitialState };
1071
893
  }
1072
- const { conditions, isWorkingSelectionChange } = payload;
894
+ const { localIdentifier, conditions, isWorkingSelectionChange } = payload;
1073
895
  const filterContextDefinition = isWorkingSelectionChange
1074
896
  ? tab.filterContext?.workingFilterContextDefinition
1075
897
  : tab.filterContext?.filterContextDefinition;
1076
- if (!isSource && !filterContextDefinition?.filters) {
1077
- return;
1078
- }
1079
898
  invariant(filterContextDefinition?.filters, "Attempt to edit uninitialized filter context");
1080
899
  const filters = filterContextDefinition.filters;
1081
900
  const index = filters.findIndex((item) => isDashboardMeasureValueFilter(item) && dashboardFilterLocalIdentifier(item) === localIdentifier);
1082
901
  const hasConditions = !!conditions && conditions.length > 0;
1083
- if (!isSource && index < 0) {
1084
- return;
1085
- }
1086
902
  invariant(index >= 0 || isWorkingSelectionChange, `Attempt to change condition of measure value filter ${localIdentifier} that does not exist`);
1087
903
  if (isWorkingSelectionChange && index < 0) {
1088
904
  const workingFilter = {
@@ -1103,48 +919,17 @@ function changeMeasureValueFilterConditionOnTab(tab, payload, localIdentifier, i
1103
919
  };
1104
920
  }
1105
921
  const setMeasureValueFilterDimensionality = (state, action) => {
1106
- const { localIdentifier, restoreTargetOriginal, enablePersistentFiltersAcrossTabs } = action.payload;
1107
- const tabs = getTabsToMutate(state, undefined, enablePersistentFiltersAcrossTabs);
1108
- const source = tabs[0];
1109
- if (!source) {
1110
- return;
1111
- }
1112
- const sourceFilter = findAppliedFilterByLocalId(source, localIdentifier);
1113
- setMeasureValueFilterDimensionalityOnTab(source, action.payload, localIdentifier, true);
1114
- if (!sourceFilter || !isDashboardMeasureValueFilter(sourceFilter)) {
922
+ const tab = getTabOrActive(state, action.payload.tabLocalIdentifier);
923
+ if (!tab) {
1115
924
  return;
1116
925
  }
1117
- for (const tab of tabs.slice(1)) {
1118
- const match = findCounterpartFilter(source, sourceFilter, tab, state.attributesWithReferences);
1119
- const targetLocalId = match ? dashboardFilterLocalIdentifier(match) : undefined;
1120
- if (!targetLocalId || !match) {
1121
- continue;
1122
- }
1123
- if (restoreTargetOriginal) {
1124
- const original = findOriginalFilter(tab, match);
1125
- if (!isDashboardMeasureValueFilter(original)) {
1126
- continue;
1127
- }
1128
- setMeasureValueFilterDimensionalityOnTab(tab, {
1129
- ...action.payload,
1130
- localIdentifier: targetLocalId,
1131
- dimensionality: original.dashboardMeasureValueFilter.dimensionality,
1132
- }, targetLocalId, false);
1133
- continue;
1134
- }
1135
- setMeasureValueFilterDimensionalityOnTab(tab, action.payload, targetLocalId, false);
1136
- }
926
+ setMeasureValueFilterDimensionalityOnTab(tab, action.payload);
1137
927
  };
1138
- function setMeasureValueFilterDimensionalityOnTab(tab, payload, localIdentifier, isSource) {
928
+ function setMeasureValueFilterDimensionalityOnTab(tab, payload) {
929
+ const { localIdentifier } = payload;
1139
930
  const filters = tab.filterContext?.filterContextDefinition?.filters;
1140
- if (!isSource && !filters) {
1141
- return;
1142
- }
1143
931
  invariant(filters, "Attempt to edit uninitialized filter context");
1144
932
  const index = filters.findIndex((item) => isDashboardMeasureValueFilter(item) && dashboardFilterLocalIdentifier(item) === localIdentifier);
1145
- if (!isSource && index < 0) {
1146
- return;
1147
- }
1148
933
  invariant(index >= 0, `Attempt to change dimensionality of measure value filter ${localIdentifier} that does not exist`);
1149
934
  const filter = filters[index];
1150
935
  const dimensionality = payload.dimensionality && payload.dimensionality.length > 0 ? payload.dimensionality : undefined;
@@ -1156,20 +941,20 @@ function setMeasureValueFilterDimensionalityOnTab(tab, payload, localIdentifier,
1156
941
  };
1157
942
  }
1158
943
  const changeMeasureValueFilterTitle = (state, action) => {
1159
- const activeTab = getActiveTab(state);
1160
- if (!activeTab) {
944
+ const { filterLocalId, title, tabLocalIdentifier } = action.payload;
945
+ const targetTab = getTabOrActive(state, tabLocalIdentifier);
946
+ if (!targetTab) {
1161
947
  return;
1162
948
  }
1163
- invariant(activeTab.filterContext?.filterContextDefinition?.filters, "Attempt to edit uninitialized filter context");
1164
- const filters = activeTab.filterContext.filterContextDefinition.filters;
1165
- const index = filters.findIndex((item) => isDashboardMeasureValueFilter(item) &&
1166
- dashboardFilterLocalIdentifier(item) === action.payload.filterLocalId);
1167
- invariant(index >= 0, `Attempt to change title of measure value filter ${action.payload.filterLocalId} that does not exist`);
949
+ const filters = targetTab.filterContext?.filterContextDefinition?.filters;
950
+ invariant(filters, "Attempt to edit uninitialized filter context");
951
+ const index = filters.findIndex((item) => isDashboardMeasureValueFilter(item) && dashboardFilterLocalIdentifier(item) === filterLocalId);
952
+ invariant(index >= 0, `Attempt to change title of measure value filter ${filterLocalId} that does not exist`);
1168
953
  const filter = filters[index];
1169
954
  filters[index] = {
1170
955
  dashboardMeasureValueFilter: {
1171
956
  ...filter.dashboardMeasureValueFilter,
1172
- title: action.payload.title,
957
+ title,
1173
958
  },
1174
959
  };
1175
960
  };