diff --git a/libs/sdk-ui-dashboard/src/model/commandHandlers/dashboard/common/stateInitializers.ts b/libs/sdk-ui-dashboard/src/model/commandHandlers/dashboard/common/stateInitializers.ts index c19965c714b..6608e255b56 100644 --- a/libs/sdk-ui-dashboard/src/model/commandHandlers/dashboard/common/stateInitializers.ts +++ b/libs/sdk-ui-dashboard/src/model/commandHandlers/dashboard/common/stateInitializers.ts @@ -66,6 +66,7 @@ export function actionsToInitializeNewDashboard( filterContextDefinition: createDefaultFilterContext(dateFilterConfig), attributeFilterDisplayForms: [], }), + filterContextActions.applyFilterContext(), layoutActions.setLayout(EmptyDashboardLayout), insightsActions.setInsights([]), metaActions.setMeta({}), @@ -280,6 +281,7 @@ export function* actionsToInitializeExistingDashboard( filterContextIdentity, attributeFilterDisplayForms, }), + filterContextActions.applyFilterContext(), layoutActions.setLayout(dashboardLayout), metaActions.setMeta({ dashboard: persistedDashboard ?? dashboard, diff --git a/libs/sdk-ui-dashboard/src/model/react/useWidgetFilters.ts b/libs/sdk-ui-dashboard/src/model/react/useWidgetFilters.ts index 9e68f97afe3..6986be466f7 100644 --- a/libs/sdk-ui-dashboard/src/model/react/useWidgetFilters.ts +++ b/libs/sdk-ui-dashboard/src/model/react/useWidgetFilters.ts @@ -1,4 +1,4 @@ -// (C) 2020-2024 GoodData Corporation +// (C) 2020-2025 GoodData Corporation import { useEffect, useMemo, useState } from "react"; import { areObjRefsEqual, @@ -19,6 +19,7 @@ import { selectFilterContextFilters, selectIsInEditMode, selectCrossFilteringFiltersLocalIdentifiersByWidgetRef, + selectAppliedFilterContextFilters, } from "../../model/store/index.js"; import { safeSerializeObjRef } from "../../_staging/metadata/safeSerializeObjRef.js"; import { FilterableDashboardWidget } from "../types/layoutTypes.js"; @@ -126,7 +127,8 @@ export function useWidgetFilters( * @param widget - widget to get the non-ignored filters for */ function useNonIgnoredFilters(widget: FilterableDashboardWidget | undefined | null) { - const dashboardFilters = useDashboardSelector(selectFilterContextFilters); + // TODO: make selector that takes into the account used filter mode + const dashboardFilters = useDashboardSelector(selectAppliedFilterContextFilters); const crossFilteringLocalIdentifiersForThisWidget = useDashboardSelector( selectCrossFilteringFiltersLocalIdentifiersByWidgetRef(widget?.ref), ); diff --git a/libs/sdk-ui-dashboard/src/model/store/filterContext/filterContextReducers.ts b/libs/sdk-ui-dashboard/src/model/store/filterContext/filterContextReducers.ts index b35e6eb62b1..811287d546f 100644 --- a/libs/sdk-ui-dashboard/src/model/store/filterContext/filterContextReducers.ts +++ b/libs/sdk-ui-dashboard/src/model/store/filterContext/filterContextReducers.ts @@ -84,6 +84,10 @@ const setFilterContext: FilterContextReducer> = (state) => { + state.appliedFilterContextDefinition = state.filterContextDefinition; +}; + // // // @@ -687,4 +691,5 @@ export const filterContextReducers = { changeSelectionMode, changeLimitingItems, setPreloadedAttributesWithReferences, + applyFilterContext, }; diff --git a/libs/sdk-ui-dashboard/src/model/store/filterContext/filterContextSelectors.ts b/libs/sdk-ui-dashboard/src/model/store/filterContext/filterContextSelectors.ts index 7787d7b80e4..1fdeb044c78 100644 --- a/libs/sdk-ui-dashboard/src/model/store/filterContext/filterContextSelectors.ts +++ b/libs/sdk-ui-dashboard/src/model/store/filterContext/filterContextSelectors.ts @@ -25,6 +25,7 @@ import isEmpty from "lodash/isEmpty.js"; import { selectSupportsCircularDependencyInFilters } from "../backendCapabilities/backendCapabilitiesSelectors.js"; import { selectCrossFilteringFiltersLocalIdentifiers } from "../drill/drillSelectors.js"; import { IAttributeWithReferences } from "@gooddata/sdk-backend-spi"; +import isEqual from "lodash/isEqual.js"; const selectSelf = createSelector( (state: DashboardState) => state, @@ -91,6 +92,16 @@ export const selectFilterContextDefinition: DashboardSelector = + createSelector(selectSelf, (filterContextState) => { + invariant( + filterContextState.appliedFilterContextDefinition, + "attempting to access uninitialized filter context state", + ); + + return filterContextState.appliedFilterContextDefinition!; + }); + /** * Selects dashboard's filter context identity. * @@ -178,6 +189,19 @@ export const selectFilterContextFilters: DashboardSelector (filterContext): FilterContextItem[] => filterContext.filters, ); +export const selectAppliedFilterContextFilters: DashboardSelector = createSelector( + selectAppliedFilterContextDefinition, + (filterContext): FilterContextItem[] => filterContext.filters, +); + +export const selectCanApplyFilterContext: DashboardSelector = createSelector( + selectFilterContextDefinition, + selectAppliedFilterContextDefinition, + (filterContextDefinition, appliedFilterContextDefinition) => { + return !isEqual(filterContextDefinition, appliedFilterContextDefinition); + }, +); + /** * This selector returns dashboard's filter context attribute filters. * diff --git a/libs/sdk-ui-dashboard/src/model/store/filterContext/filterContextState.ts b/libs/sdk-ui-dashboard/src/model/store/filterContext/filterContextState.ts index 6cd278358f2..ae5ae8e01b1 100644 --- a/libs/sdk-ui-dashboard/src/model/store/filterContext/filterContextState.ts +++ b/libs/sdk-ui-dashboard/src/model/store/filterContext/filterContextState.ts @@ -17,6 +17,13 @@ export interface FilterContextState { */ filterContextDefinition?: IFilterContextDefinition; + /** + * For "apply all" filter bar mode, this contains the filter context definition that is applied to the dashboard, + * and should be used for the executions. + * @beta + */ + appliedFilterContextDefinition?: IFilterContextDefinition; + /** * Filter context definition contains the original dashboard filters stored on the backend. * @beta @@ -56,6 +63,7 @@ export interface FilterContextState { export const filterContextInitialState: FilterContextState = { filterContextDefinition: undefined, + appliedFilterContextDefinition: undefined, filterContextIdentity: undefined, attributeFilterDisplayForms: undefined, attributesWithReferences: undefined, diff --git a/libs/sdk-ui-dashboard/src/model/store/index.ts b/libs/sdk-ui-dashboard/src/model/store/index.ts index e5a2021f1cb..767846e25ef 100644 --- a/libs/sdk-ui-dashboard/src/model/store/index.ts +++ b/libs/sdk-ui-dashboard/src/model/store/index.ts @@ -172,6 +172,9 @@ export { selectIsAttributeFilterDependentByLocalIdentifier, selectFilterContextDateFilterByDataSet, selectPreloadedAttributesWithReferences, + selectAppliedFilterContextDefinition, + selectAppliedFilterContextFilters, + selectCanApplyFilterContext, } from "./filterContext/filterContextSelectors.js"; export type { IImplicitDrillWithPredicates } from "./widgetDrills/widgetDrillSelectors.js"; export { diff --git a/libs/sdk-ui-dashboard/src/presentation/filterBar/filterBar/DefaultFilterBarContainer.tsx b/libs/sdk-ui-dashboard/src/presentation/filterBar/filterBar/DefaultFilterBarContainer.tsx index 98a4e83adc1..33934fcf9f0 100644 --- a/libs/sdk-ui-dashboard/src/presentation/filterBar/filterBar/DefaultFilterBarContainer.tsx +++ b/libs/sdk-ui-dashboard/src/presentation/filterBar/filterBar/DefaultFilterBarContainer.tsx @@ -1,5 +1,5 @@ -// (C) 2021-2024 GoodData Corporation -import React, { useRef } from "react"; +// (C) 2021-2025 GoodData Corporation +import React, { useCallback, useRef } from "react"; import DefaultMeasure from "react-measure"; import cx from "classnames"; import { createSelector } from "@reduxjs/toolkit"; @@ -14,6 +14,8 @@ import { useDashboardSelector, selectEnableFilterViews, selectEnableFlexibleLayout, + selectCanApplyFilterContext, + useDashboardDispatch, } from "../../../model/index.js"; import { ShowAllFiltersButton } from "./ShowAllFiltersButton.js"; @@ -24,6 +26,9 @@ import { FiltersConfigurationPanel } from "./FiltersConfigurationPanel.js"; import { FilterViews } from "./filterViews/FilterViews.js"; import { BulletsBar as FlexibleBulletsBar } from "../../flexibleLayout/dragAndDrop/Resize/BulletsBar/BulletsBar.js"; import { BulletsBar as FluidBulletsBar } from "../../layout/dragAndDrop/Resize/BulletsBar/BulletsBar.js"; +import { UiButton } from "@gooddata/sdk-ui-kit"; +// TODO: this should be proper dashboard command +import { filterContextActions } from "../../../model/store/filterContext/index.js"; const selectShowFiltersConfigurationPanel = createSelector( selectIsInEditMode, @@ -52,6 +57,12 @@ const DefaultFilterBarContainerCore: React.FC<{ children?: React.ReactNode }> = const showFiltersConfigurationPanel = useDashboardSelector(selectShowFiltersConfigurationPanel); const isFilterViewsFeatureFlagEnabled = useDashboardSelector(selectEnableFilterViews); const isFlexibleLayoutEnabled = useDashboardSelector(selectEnableFlexibleLayout); + const canApplyFilterContext = useDashboardSelector(selectCanApplyFilterContext); + const dispatch = useDashboardDispatch(); + + const applyFilterContext = useCallback(() => { + dispatch(filterContextActions.applyFilterContext()); + }, [dispatch]); return (
@@ -65,6 +76,13 @@ const DefaultFilterBarContainerCore: React.FC<{ children?: React.ReactNode }> = {children}
+ {isFilterViewsFeatureFlagEnabled ? : null} {showFiltersConfigurationPanel ? : null}