Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,19 @@ import {
OldJsonTree,
Utils as QbUtils,
} from '@react-awesome-query-builder/antd';
import { isEmpty, isEqual, isNil, isString } from 'lodash';
import { isEmpty, isArray, isEqual, isNil, isString } from 'lodash';
import Qs from 'qs';
import {
createContext,
useCallback,
useContext,
useEffect,
useMemo,
useRef,
useState,
} from 'react';
import { useNavigate } from 'react-router-dom';
import { EntityType } from '../../../enums/entity.enum';
import { SearchIndex } from '../../../enums/search.enum';
import useCustomLocation from '../../../hooks/useCustomLocation/useCustomLocation';
import { TabsInfoData } from '../../../pages/ExplorePage/ExplorePage.interface';
Expand Down Expand Up @@ -88,10 +90,36 @@ export const AdvanceSearchProvider = ({
null
);

// Tracks which effectiveEntityType was used to populate the customProps cache
// (e.g., "databaseSchema" when the user is on the Database Schema explore tab,
// or undefined when showing all entity types). The cache must be invalidated
// whenever users switch between explore tabs so that extension field paths are
// rebuilt for the new entity type context.
const customPropsEntityTypeRef = useRef<string | undefined>(undefined);

const [searchIndex, setSearchIndex] = useState<
SearchIndex | Array<SearchIndex>
>(getSearchIndexFromTabInfo(tabsInfo, tab));

// When entityType is not explicitly provided, derive it from the current searchIndex
// so that custom property extension field paths do not include the entity type namespace
// prefix. The Elasticsearch `extension` field uses the `flattened` type and stores data
// WITHOUT the entity type prefix (e.g., key is "informationOwners.displayName", not
// "databaseSchema.informationOwners.displayName"), so omitting the prefix is required
// for queries to match actual documents.
const effectiveEntityType = useMemo(() => {
if (entityType) {
return entityType;
}
if (isArray(searchIndex)) {
return undefined;
}
const mapping = searchClassBase.getSearchIndexEntityTypeMapping();
const mapped = mapping[searchIndex];
Comment on lines +114 to +118
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

effectiveEntityType returns undefined for any array searchIndex, even when the array contains a single index. In flows that pass a single selected entity as an array (e.g., onChangeSearchIndex([SearchIndex.TABLE])), this keeps the old extension namespace behavior and can reintroduce the same custom-property query mismatch. Consider deriving the entity type when searchIndex is an array of length 1 (and only treating it as multi-entity when length > 1).

Suggested change
if (isArray(searchIndex)) {
return undefined;
}
const mapping = searchClassBase.getSearchIndexEntityTypeMapping();
const mapped = mapping[searchIndex];
const normalizedSearchIndex = isArray(searchIndex)
? searchIndex.length === 1
? searchIndex[0]
: undefined
: searchIndex;
if (isNil(normalizedSearchIndex)) {
return undefined;
}
const mapping = searchClassBase.getSearchIndexEntityTypeMapping();
const mapped = mapping[normalizedSearchIndex];

Copilot uses AI. Check for mistakes.
// EntityType.ALL represents a multi-entity context — preserve namespace prefixes
return mapped && mapped !== EntityType.ALL ? mapped : undefined;
}, [entityType, searchIndex]);
Comment on lines +104 to +121
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change alters how custom property paths are generated (deriving an effective entity type from searchIndex and changing cache invalidation). There’s currently no active unit test covering the Explore-tab scenario where entityType is undefined and ensuring extension fields are built without the entity-type namespace. Please add/enable a test that asserts fetchCustomPropertyType/processEntityTypeFields are invoked with the derived entity type (e.g., DATABASE_SCHEMA → "databaseSchema") and that switching tabs causes the customProps cache to be refetched with the new context.

Copilot uses AI. Check for mistakes.

const changeSearchIndex = useCallback(
(index: SearchIndex | Array<SearchIndex>) => {
setIsUpdating(true);
Expand Down Expand Up @@ -231,7 +259,7 @@ export const AdvanceSearchProvider = ({
resEntityType,
fields,
subfields,
entityType,
effectiveEntityType,
searchOutputType
);
});
Expand All @@ -249,10 +277,18 @@ export const AdvanceSearchProvider = ({
isExplorePage,
});

let extensionSubField = customProps;
// Use cached custom properties only if the effective entity type matches the
// context used to build the cache. When users switch explore tabs the entity
// type changes, so the cache must be refetched to rebuild extension field paths
// with the correct namespace context for the new entity type.
let extensionSubField =
customPropsEntityTypeRef.current === effectiveEntityType
? customProps
: null;
if (extensionSubField === null) {
extensionSubField = await fetchCustomPropertyType();
setCustomProps(extensionSubField);
customPropsEntityTypeRef.current = effectiveEntityType;
Comment on lines +284 to +291
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change causes getAllCustomProperties() to be re-fetched whenever effectiveEntityType changes (e.g., each Explore tab switch). Since the API response is global and only the derived subfields shape changes, consider caching the raw custom properties response once and rebuilding extensionSubField locally per entity type (or caching computed subfields per entity type) to avoid repeated network calls and recomputation.

Copilot uses AI. Check for mistakes.
}
Comment on lines 288 to 292
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

loadData() can run concurrently when users switch tabs quickly (it’s triggered by searchIndex changes). Because it awaits fetchCustomPropertyType() and then updates customProps and customPropsEntityTypeRef, a slower previous request can complete after a newer one and overwrite the cache/ref for the current tab. Consider guarding with a monotonically increasing request id / "latest only" check (or abort/cancel) before applying setCustomProps, customPropsEntityTypeRef.current = ..., and setConfig.

Copilot uses AI. Check for mistakes.

if (
Expand Down
Loading