Skip to content

Commit

Permalink
Merge pull request #5086 from gooddata/ine-lx-317
Browse files Browse the repository at this point in the history
fix: repare some AF use cases + KD config preparation
  • Loading branch information
xMort authored Jul 2, 2024
2 parents 12e9598 + 0bd16f5 commit 774c5c7
Show file tree
Hide file tree
Showing 14 changed files with 87 additions and 33 deletions.
1 change: 1 addition & 0 deletions libs/sdk-model/api/sdk-model.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -1048,6 +1048,7 @@ export interface IDashboardAttributeFilterByDate {

// @alpha
export interface IDashboardAttributeFilterConfig {
displayAsLabel?: ObjRef;
localIdentifier: string;
mode?: DashboardAttributeFilterConfigMode;
}
Expand Down
5 changes: 5 additions & 0 deletions libs/sdk-model/src/dashboard/dashboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,11 @@ export interface IDashboardAttributeFilterConfig {
* Control visibility mode of the attribute filter
*/
mode?: DashboardAttributeFilterConfigMode;

/**
* Display form to use to show elements of attribute filter in UI
*/
displayAsLabel?: ObjRef;
}

/**
Expand Down
4 changes: 2 additions & 2 deletions libs/sdk-ui-filters/api/sdk-ui-filters.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,8 @@ export interface IAttributeElementLoader {
onLoadNextElementsPageError: CallbackRegistration<OnLoadNextElementsPageErrorCallbackPayload>;
onLoadNextElementsPageStart: CallbackRegistration<OnLoadNextElementsPageStartCallbackPayload>;
onLoadNextElementsPageSuccess: CallbackRegistration<OnLoadNextElementsPageSuccessCallbackPayload>;
setDisplayAsLabel(displayAsLabel: ObjRef): void;
setDisplayForm(displayForm: ObjRef): void;
setLimit(limit: number): void;
setLimitingAttributeFilters(filters: IElementsQueryAttributeFilter[]): void;
setLimitingDateFilters(filters: (IRelativeDateFilter | IAbsoluteDateFilter)[]): void;
Expand Down Expand Up @@ -612,8 +614,6 @@ export interface IAttributeFilterLoader extends IAttributeLoader, IAttributeElem
onInitStart: CallbackRegistration<OnInitStartCallbackPayload>;
onInitSuccess: CallbackRegistration<OnInitSuccessCallbackPayload>;
onUpdate: CallbackRegistration<void>;
// (undocumented)
setDisplayAsLabel(displayAsLabel: ObjRef): void;
}

// @beta
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
filterAttributeElements,
filterObjRef,
IAbsoluteDateFilter,
IAttributeDisplayFormMetadataObject,
IAttributeElement,
IAttributeFilter,
IRelativeDateFilter,
Expand Down Expand Up @@ -189,6 +190,7 @@ export const useAttributeFilterController = (
selectFirst,
onApply: callbacks.onApply,
selectionMode,
enableDuplicatedLabelValuesInAttributeFilter,
});

return {
Expand Down Expand Up @@ -332,6 +334,7 @@ function useInitOrReload(
setShouldReloadElements,
limitingValidationItems,
limitingValidationItemsChanged,
displayAsLabel,
};

const change = resetOnParentFilterChange
Expand All @@ -351,6 +354,7 @@ function useInitOrReload(
supportsCircularDependencyInFilters,
setShouldReloadElements,
limitingValidationItems,
displayAsLabel,
]);

const isMountedRef = useRef(false);
Expand Down Expand Up @@ -393,6 +397,7 @@ function useInitOrReload(

type UpdateFilterProps = {
filter: IAttributeFilter;
displayAsLabel: ObjRef;
limitingAttributeFilters?: IElementsQueryAttributeFilter[];
limitingAttributesChanged: boolean;
limitingDateFilters?: (IRelativeDateFilter | IAbsoluteDateFilter)[];
Expand Down Expand Up @@ -421,6 +426,7 @@ function updateNonResettingFilter(
setShouldReloadElements,
limitingValidationItemsChanged,
limitingValidationItems,
displayAsLabel,
}: UpdateFilterProps,
supportsKeepingDependentFiltersSelection: boolean,
): UpdateFilterType {
Expand Down Expand Up @@ -451,11 +457,16 @@ function updateNonResettingFilter(
!isEmpty(leftoverIrrelevantKeys));

const irrelevantKeysObj = shouldReinitilizeAllElements ? { irrelevantKeys: [] } : {};
handler.changeSelection({ keys, isInverted, ...irrelevantKeysObj });
if (filterChanged || !supportsKeepingDependentFiltersSelection || shouldReinitilizeAllElements) {
const displayFormRef = filterObjRef(filter);
handler.setDisplayForm(displayFormRef);
handler.setDisplayAsLabel(displayAsLabel);
handler.changeSelection({ keys, isInverted, ...irrelevantKeysObj });
handler.commitSelection();
}
handler.setLimitingAttributeFilters(limitingAttributeFilters);
handler.setLimitingValidationItems(limitingValidationItems);
handler.setLimitingDateFilters(limitingDateFilters);
handler.commitSelection();

const nextFilter = handler.getFilter();
setConnectedPlaceholderValue(nextFilter);
Expand Down Expand Up @@ -484,6 +495,7 @@ function updateAutomaticResettingFilter(
setConnectedPlaceholderValue,
onApply,
selectionMode,
displayAsLabel,
}: UpdateFilterProps,
supportsCircularDependencyInFilters: boolean,
): UpdateFilterType {
Expand Down Expand Up @@ -515,10 +527,15 @@ function updateAutomaticResettingFilter(
}

if (filterChanged) {
// reset handler completely to match input filter
// label could change as a part of migration to the primary label
const displayFormRef = filterObjRef(filter);
const elements = filterAttributeElements(filter);
const keys = isAttributeElementsByValue(elements) ? elements.values : elements.uris;
const isInverted = isNegativeAttributeFilter(filter);

handler.setDisplayForm(displayFormRef);
handler.setDisplayAsLabel(displayAsLabel);
handler.changeSelection({ keys, isInverted });
handler.commitSelection();

Expand Down Expand Up @@ -741,11 +758,12 @@ const useSingleSelectModeHandler = (
selectFirst: boolean;
selectionMode: DashboardAttributeFilterSelectionMode;
onApply: () => void;
enableDuplicatedLabelValuesInAttributeFilter: boolean;
},
) => {
const { selectFirst, selectionMode, onApply } = props;
const { selectFirst, selectionMode, onApply, enableDuplicatedLabelValuesInAttributeFilter } = props;
const committedSelectionKeys = handler.getCommittedSelection().keys;
const initialElementsPageStatus = handler.getInitialElementsPageStatus();
const initialStatus = handler.getInitStatus();
const elements = handler.getAllElements();
const filter = handler.getFilter();

Expand All @@ -754,11 +772,15 @@ const useSingleSelectModeHandler = (
selectFirst &&
selectionMode === "single" &&
isEmpty(committedSelectionKeys) &&
initialElementsPageStatus === "success" &&
initialStatus === "success" &&
!isEmpty(elements)
) {
const isElementsByRef = isAttributeElementsByRef(filterAttributeElements(filter));
const keys = [isElementsByRef ? elements[0].uri : elements[0].title];
const keys = [
isElementsByRef || enableDuplicatedLabelValuesInAttributeFilter
? elements[0].uri
: elements[0].title,
];

handler.changeSelection({ keys, isInverted: false, irrelevantKeys: [] });
handler.commitSelection();
Expand All @@ -768,11 +790,12 @@ const useSingleSelectModeHandler = (
selectFirst,
selectionMode,
committedSelectionKeys,
initialElementsPageStatus,
initialStatus,
elements,
filter,
handler,
onApply,
enableDuplicatedLabelValuesInAttributeFilter,
]);
};

Expand Down Expand Up @@ -823,7 +846,7 @@ const useShouldIncludeLimitingFilters = (supportsShowingFilteredElements: boolea
};
function isPrimaryLabelUsed(
filter: IAttributeFilter,
displayForms: import("@gooddata/sdk-model").IAttributeDisplayFormMetadataObject[],
displayForms: IAttributeDisplayFormMetadataObject[],
): boolean {
const primaryDisplayForm = displayForms.find((df) => df.isPrimary);
if (!primaryDisplayForm) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,9 @@ export class AttributeFilterReduxBridge {
setDisplayAsLabel = (displayAsLabel: ObjRef, correlation?: Correlation): void => {
this.redux.dispatch(actions.setDisplayAsLabel({ displayAsLabel, correlation }));
};
setDisplayForm = (displayForm: ObjRef, correlation?: Correlation): void => {
this.redux.dispatch(actions.setDisplayFormRef({ displayForm, correlation }));
};

getOffset = (): number => {
return this.redux.select(selectOffset);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,9 @@ export class AttributeFilterLoader implements IAttributeFilterLoader {
setDisplayAsLabel = (displayAsLabel: ObjRef): void => {
this.bridge.setDisplayAsLabel(displayAsLabel);
};
setDisplayForm = (label: ObjRef): void => {
this.bridge.setDisplayForm(label);
};

getOffset = (): number => {
return this.bridge.getOffset();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,32 @@ import { PayloadAction } from "@reduxjs/toolkit";

import { Correlation } from "../../../types/index.js";
import { AttributeFilterReducer } from "../store/state.js";
import { ObjRef } from "@gooddata/sdk-model";
import { ObjRef, areObjRefsEqual } from "@gooddata/sdk-model";

const transformFilterToPrimaryLabel: AttributeFilterReducer<
PayloadAction<{ primaryLabelRef: ObjRef; secondaryLabelRef: ObjRef; correlation: Correlation }>
> = (state, action) => {
// this switch of display forms transforms old filters saved with secondary label in them to attributes primary label and backup secondary label to the new property
state.displayFormRef = action.payload.primaryLabelRef;
if (!state.displayAsDisplayFormRef) {
if (!state.displayAsLabelRef) {
// do not override already defined custom display form during migration
state.displayAsDisplayFormRef = action.payload.secondaryLabelRef;
state.displayAsLabelRef = action.payload.secondaryLabelRef;
}
};

const setDisplayAsLabel: AttributeFilterReducer<
PayloadAction<{ displayAsLabel: ObjRef; correlation: Correlation }>
> = (state, action) => {
state.displayAsDisplayFormRef = action.payload.displayAsLabel;
state.elements.cache = {};
if (!areObjRefsEqual(state.displayAsLabelRef, action.payload.displayAsLabel)) {
state.elements.cache = {};
}
state.displayAsLabelRef = action.payload.displayAsLabel;
};

const setDisplayFormRef: AttributeFilterReducer<
PayloadAction<{ displayForm: ObjRef; correlation: Correlation }>
> = (state, action) => {
state.displayFormRef = action.payload.displayForm;
};

/**
Expand All @@ -29,4 +37,5 @@ const setDisplayAsLabel: AttributeFilterReducer<
export const displayFormsReducers = {
transformFilterToPrimaryLabel,
setDisplayAsLabel,
setDisplayFormRef,
};
Original file line number Diff line number Diff line change
Expand Up @@ -34,30 +34,32 @@ export function* elementsSaga(
selectAttributeFilterDisplayForm,
);

const attributeFilterDisplayAsDisplayFormRef: ReturnType<typeof selectAttributeFilterDisplayAsLabel> =
const attributeFilterDisplayAsLabelRef: ReturnType<typeof selectAttributeFilterDisplayAsLabel> =
yield select(selectAttributeFilterDisplayAsLabel);

const staticElements: ReturnType<typeof selectStaticElements> = yield select(selectStaticElements);

const { enableDuplicatedLabelValuesInAttributeFilter } = context;

const filterByPrimaryLabelProp =
enableDuplicatedLabelValuesInAttributeFilter &&
attributeFilterDisplayAsDisplayFormRef &&
!options.search // when searching by string, we need to apply it to the displayAsLabel directly not primary label
enableDuplicatedLabelValuesInAttributeFilter && attributeFilterDisplayAsLabelRef && !options.search // when searching by string, we need to apply it to the displayAsLabel directly not primary label
? { filterByPrimaryLabel: true }
: {};

const allOptions = {
...options,
...filterByPrimaryLabelProp,
};

const elementsQueryResult: PromiseFnReturnType<typeof loadElements> = yield call(
loadElements,
context,
{
displayFormRef:
enableDuplicatedLabelValuesInAttributeFilter && attributeFilterDisplayAsDisplayFormRef
? attributeFilterDisplayAsDisplayFormRef
enableDuplicatedLabelValuesInAttributeFilter && attributeFilterDisplayAsLabelRef
? attributeFilterDisplayAsLabelRef
: attributeFilterDisplayFormRef,
...options,
...filterByPrimaryLabelProp,
...allOptions,
},
{
hiddenElements,
Expand All @@ -70,7 +72,7 @@ export function* elementsSaga(
return {
elements: elementsQueryResult.items,
totalCount: elementsQueryResult.totalCount,
options: omit(options, "signal"),
options: omit(allOptions, "signal"),
cacheId: elementsQueryResult.cacheId,
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export const selectAttributeFilterDisplayForm: FilterSelector<ObjRef> = createSe
*/
export const selectAttributeFilterDisplayAsLabel: FilterSelector<ObjRef> = createSelector(
selectState,
(state) => state.displayAsDisplayFormRef,
(state) => state.displayAsLabelRef,
);

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,15 @@ const loadCustomElementsSuccess: AttributeFilterReducer<

const {
enableDuplicatedLabelValuesInAttributeFilter,
options: { elements },
options: { elements, filterByPrimaryLabel },
} = action.payload;
if (elements) {
if (enableDuplicatedLabelValuesInAttributeFilter && elements) {
const originalElements = getElementValues(elements);
// iterate over original elements to keep the order in selection,
// fetched elements are sorted by default
originalElements.forEach((originalEl) => {
action.payload.elements
.filter((el) => el.title === originalEl)
.filter((el) => (filterByPrimaryLabel ? el.uri === originalEl : el.title === originalEl))
.forEach((el) => {
const cacheKey = getElementCacheKey(
state,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export function createAttributeFilterHandlerStore(
...initialState,
localIdentifier,
displayFormRef,
displayAsDisplayFormRef: context.displayAsLabel,
displayAsLabelRef: context.displayAsLabel,
elementsForm,
selection: {
commited: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { ILoadElementsOptions, AsyncOperationStatus } from "../../../types/index
export interface AttributeFilterState {
localIdentifier?: string;
displayFormRef: ObjRef; // primary label used for execution
displayAsDisplayFormRef?: ObjRef; // optional secondary label used for display elements in filter component
displayAsLabelRef?: ObjRef; // optional secondary label used for display elements in filter component
elementsForm: "uris" | "values";
initialization: {
status: AsyncOperationStatus;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// (C) 2022-2024 GoodData Corporation
import { IAttributeFilter, ObjRef } from "@gooddata/sdk-model";
import { IAttributeFilter } from "@gooddata/sdk-model";
import { GoodDataSdkError } from "@gooddata/sdk-ui";
import {
AsyncOperationStatus,
Expand Down Expand Up @@ -41,8 +41,6 @@ export interface IAttributeFilterLoader extends IAttributeLoader, IAttributeElem
*/
init(correlation?: Correlation): void;

setDisplayAsLabel(displayAsLabel: ObjRef): void;

/**
* Returns the current status of the initialization.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,16 @@ export interface IAttributeElementLoader {
*/
cancelIrrelevantElementsLoad(correlation?: Correlation): void;

/**
* Set attribute's display form
*/
setDisplayForm(displayForm: ObjRef): void;

/**
* Set the label used for representing the attribute filter elements visually.
*/
setDisplayAsLabel(displayAsLabel: ObjRef): void;

/**
* Set the limit for the upcoming attribute element loads.
*
Expand Down

0 comments on commit 774c5c7

Please sign in to comment.