mirror of
https://github.com/datahub-project/datahub.git
synced 2025-11-14 18:31:59 +00:00
fix(summary-tab): fix structured property value type issue (#14644)
Co-authored-by: Chris Collins <chriscollins3456@gmail.com>
This commit is contained in:
parent
4341e64732
commit
03bca391d3
@ -10,12 +10,12 @@ import EditStructuredPropertyModal from '@app/entity/shared/tabs/Properties/Edit
|
|||||||
import { Icon, Input as InputComponent, Text, colors } from '@src/alchemy-components';
|
import { Icon, Input as InputComponent, Text, colors } from '@src/alchemy-components';
|
||||||
import { useUserContext } from '@src/app/context/useUserContext';
|
import { useUserContext } from '@src/app/context/useUserContext';
|
||||||
import { REDESIGN_COLORS } from '@src/app/entityV2/shared/constants';
|
import { REDESIGN_COLORS } from '@src/app/entityV2/shared/constants';
|
||||||
import { getEntityTypesPropertyFilter, getNotHiddenPropertyFilter } from '@src/app/govern/structuredProperties/utils';
|
import { getStructuredPropertiesSearchInputs } from '@src/app/govern/structuredProperties/utils';
|
||||||
import { useEntityRegistry } from '@src/app/useEntityRegistry';
|
import { useEntityRegistry } from '@src/app/useEntityRegistry';
|
||||||
import { useIsThemeV2 } from '@src/app/useIsThemeV2';
|
import { useIsThemeV2 } from '@src/app/useIsThemeV2';
|
||||||
import { PageRoutes } from '@src/conf/Global';
|
import { PageRoutes } from '@src/conf/Global';
|
||||||
import { useGetSearchResultsForMultipleQuery } from '@src/graphql/search.generated';
|
import { useGetSearchResultsForMultipleQuery } from '@src/graphql/search.generated';
|
||||||
import { EntityType, Maybe, StructuredProperties, StructuredPropertyEntity } from '@src/types.generated';
|
import { Maybe, StructuredProperties, StructuredPropertyEntity } from '@src/types.generated';
|
||||||
|
|
||||||
const AddButton = styled.div<{ isThemeV2: boolean; isV1Drawer?: boolean }>`
|
const AddButton = styled.div<{ isThemeV2: boolean; isV1Drawer?: boolean }>`
|
||||||
border-radius: 200px;
|
border-radius: 200px;
|
||||||
@ -87,26 +87,10 @@ const AddPropertyButton = ({ fieldUrn, refetch, fieldProperties, isV1Drawer }: P
|
|||||||
const entityRegistry = useEntityRegistry();
|
const entityRegistry = useEntityRegistry();
|
||||||
const [isEditModalVisible, setIsEditModalVisible] = useState(false);
|
const [isEditModalVisible, setIsEditModalVisible] = useState(false);
|
||||||
|
|
||||||
const inputs = {
|
|
||||||
types: [EntityType.StructuredProperty],
|
|
||||||
query: '',
|
|
||||||
start: 0,
|
|
||||||
count: 100,
|
|
||||||
searchFlags: { skipCache: true },
|
|
||||||
orFilters: [
|
|
||||||
{
|
|
||||||
and: [
|
|
||||||
getEntityTypesPropertyFilter(entityRegistry, !!fieldUrn, entityType),
|
|
||||||
getNotHiddenPropertyFilter(),
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
// Execute search
|
// Execute search
|
||||||
const { data, loading } = useGetSearchResultsForMultipleQuery({
|
const { data, loading } = useGetSearchResultsForMultipleQuery({
|
||||||
variables: {
|
variables: {
|
||||||
input: inputs,
|
input: getStructuredPropertiesSearchInputs(entityRegistry, entityType, fieldUrn, searchQuery),
|
||||||
},
|
},
|
||||||
fetchPolicy: 'cache-first',
|
fetchPolicy: 'cache-first',
|
||||||
});
|
});
|
||||||
@ -157,9 +141,6 @@ const AddPropertyButton = ({ fieldUrn, refetch, fieldProperties, isV1Drawer }: P
|
|||||||
|
|
||||||
if (!canEditProperties) return null;
|
if (!canEditProperties) return null;
|
||||||
|
|
||||||
// Filter items based on search query
|
|
||||||
const filteredItems = properties?.filter((prop) => prop.name?.toLowerCase().includes(searchQuery.toLowerCase()));
|
|
||||||
|
|
||||||
const noDataText =
|
const noDataText =
|
||||||
properties?.length === 0 ? (
|
properties?.length === 0 ? (
|
||||||
<>
|
<>
|
||||||
@ -177,7 +158,7 @@ const AddPropertyButton = ({ fieldUrn, refetch, fieldProperties, isV1Drawer }: P
|
|||||||
<>
|
<>
|
||||||
<Dropdown
|
<Dropdown
|
||||||
trigger={['click']}
|
trigger={['click']}
|
||||||
menu={{ items: filteredItems }}
|
menu={{ items: properties }}
|
||||||
dropdownRender={(menuNode) => (
|
dropdownRender={(menuNode) => (
|
||||||
<DropdownContainer>
|
<DropdownContainer>
|
||||||
<SearchContainer>
|
<SearchContainer>
|
||||||
@ -195,7 +176,7 @@ const AddPropertyButton = ({ fieldUrn, refetch, fieldProperties, isV1Drawer }: P
|
|||||||
</LoadingContainer>
|
</LoadingContainer>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
{filteredItems?.length === 0 && (
|
{properties?.length === 0 && (
|
||||||
<EmptyContainer>
|
<EmptyContainer>
|
||||||
<Text color="gray" weight="medium">
|
<Text color="gray" weight="medium">
|
||||||
No results found
|
No results found
|
||||||
|
|||||||
@ -20,6 +20,7 @@ vi.mock('@app/govern/structuredProperties/utils', async () => {
|
|||||||
getNotHiddenPropertyFilter: vi.fn(),
|
getNotHiddenPropertyFilter: vi.fn(),
|
||||||
getValueTypeFilter: vi.fn(),
|
getValueTypeFilter: vi.fn(),
|
||||||
getDisplayNameFilter: vi.fn(),
|
getDisplayNameFilter: vi.fn(),
|
||||||
|
getStructuredPropertiesSearchInputs: vi.fn(),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -33,6 +34,9 @@ const mockSearchResults = {
|
|||||||
urn: 'urn1',
|
urn: 'urn1',
|
||||||
definition: {
|
definition: {
|
||||||
displayName: 'First Property',
|
displayName: 'First Property',
|
||||||
|
valueType: {
|
||||||
|
urn: 'urn:li:dataType:datahub.string',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -43,6 +47,22 @@ const mockSearchResults = {
|
|||||||
urn: 'urn2',
|
urn: 'urn2',
|
||||||
definition: {
|
definition: {
|
||||||
displayName: 'Second Property',
|
displayName: 'Second Property',
|
||||||
|
valueType: {
|
||||||
|
urn: 'urn:li:dataType:datahub.string',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
entity: {
|
||||||
|
__typename: 'StructuredProperty',
|
||||||
|
type: EntityType.StructuredProperty,
|
||||||
|
urn: 'urn3',
|
||||||
|
definition: {
|
||||||
|
displayName: 'Rich Text Property',
|
||||||
|
valueType: {
|
||||||
|
urn: 'urn:li:dataType:datahub.rich_text', // should get filtered out
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -66,6 +86,7 @@ describe('useStructuredProperties', () => {
|
|||||||
(governUtils.getNotHiddenPropertyFilter as any).mockReturnValue({ field: 'test', values: [] });
|
(governUtils.getNotHiddenPropertyFilter as any).mockReturnValue({ field: 'test', values: [] });
|
||||||
(governUtils.getValueTypeFilter as any).mockReturnValue({ field: 'test', values: [] });
|
(governUtils.getValueTypeFilter as any).mockReturnValue({ field: 'test', values: [] });
|
||||||
(governUtils.getDisplayNameFilter as any).mockReturnValue({ field: 'test', values: [] });
|
(governUtils.getDisplayNameFilter as any).mockReturnValue({ field: 'test', values: [] });
|
||||||
|
(governUtils.getStructuredPropertiesSearchInputs as any).mockReturnValue({ field: 'test', values: [] });
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should correctly map search results to AssetProperty', () => {
|
it('should correctly map search results to AssetProperty', () => {
|
||||||
@ -83,12 +104,6 @@ describe('useStructuredProperties', () => {
|
|||||||
expect(firstProperty.structuredProperty?.definition.displayName).toBe('First Property');
|
expect(firstProperty.structuredProperty?.definition.displayName).toBe('First Property');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call getDisplayNameFilter when a query is provided', () => {
|
|
||||||
(useGetSearchResultsForMultipleQuery as any).mockReturnValue({ data: null, loading: false });
|
|
||||||
renderHook(() => useStructuredProperties('test query'));
|
|
||||||
expect(governUtils.getDisplayNameFilter).toHaveBeenCalledWith('test query');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not call getDisplayNameFilter when query is empty', () => {
|
it('should not call getDisplayNameFilter when query is empty', () => {
|
||||||
(useGetSearchResultsForMultipleQuery as any).mockReturnValue({ data: null, loading: false });
|
(useGetSearchResultsForMultipleQuery as any).mockReturnValue({ data: null, loading: false });
|
||||||
renderHook(() => useStructuredProperties(''));
|
renderHook(() => useStructuredProperties(''));
|
||||||
|
|||||||
@ -3,19 +3,11 @@ import { useMemo } from 'react';
|
|||||||
import { useEntityData } from '@app/entity/shared/EntityContext';
|
import { useEntityData } from '@app/entity/shared/EntityContext';
|
||||||
import { SUPPORTED_STRUCTURED_PROPERTY_VALUE_TYPES } from '@app/entityV2/summary/properties/constants';
|
import { SUPPORTED_STRUCTURED_PROPERTY_VALUE_TYPES } from '@app/entityV2/summary/properties/constants';
|
||||||
import { AssetProperty } from '@app/entityV2/summary/properties/types';
|
import { AssetProperty } from '@app/entityV2/summary/properties/types';
|
||||||
import {
|
import { getStructuredPropertiesSearchInputs, isStructuredProperty } from '@app/govern/structuredProperties/utils';
|
||||||
getDisplayNameFilter,
|
|
||||||
getEntityTypesPropertyFilter,
|
|
||||||
getNotHiddenPropertyFilter,
|
|
||||||
getValueTypeFilter,
|
|
||||||
isStructuredProperty,
|
|
||||||
} from '@app/govern/structuredProperties/utils';
|
|
||||||
import { useEntityRegistry } from '@app/useEntityRegistry';
|
import { useEntityRegistry } from '@app/useEntityRegistry';
|
||||||
|
|
||||||
import { useGetSearchResultsForMultipleQuery } from '@graphql/search.generated';
|
import { useGetSearchResultsForMultipleQuery } from '@graphql/search.generated';
|
||||||
import { EntityType, SummaryElementType } from '@types';
|
import { SummaryElementType } from '@types';
|
||||||
|
|
||||||
const MAX_PROPERTIES = 20;
|
|
||||||
|
|
||||||
export default function useStructuredProperties(query: string | undefined) {
|
export default function useStructuredProperties(query: string | undefined) {
|
||||||
const { entityType } = useEntityData();
|
const { entityType } = useEntityData();
|
||||||
@ -59,27 +51,9 @@ export default function useStructuredProperties(query: string | undefined) {
|
|||||||
|
|
||||||
// SEARCH API
|
// SEARCH API
|
||||||
|
|
||||||
const inputs = {
|
|
||||||
types: [EntityType.StructuredProperty],
|
|
||||||
query: '*',
|
|
||||||
start: 0,
|
|
||||||
count: MAX_PROPERTIES,
|
|
||||||
searchFlags: { skipCache: true },
|
|
||||||
orFilters: [
|
|
||||||
{
|
|
||||||
and: [
|
|
||||||
getEntityTypesPropertyFilter(entityRegistry, false, entityType),
|
|
||||||
getNotHiddenPropertyFilter(),
|
|
||||||
getValueTypeFilter(SUPPORTED_STRUCTURED_PROPERTY_VALUE_TYPES),
|
|
||||||
...(preprocessedQuery ? [getDisplayNameFilter(preprocessedQuery)] : []),
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
const { data, loading } = useGetSearchResultsForMultipleQuery({
|
const { data, loading } = useGetSearchResultsForMultipleQuery({
|
||||||
variables: {
|
variables: {
|
||||||
input: inputs,
|
input: getStructuredPropertiesSearchInputs(entityRegistry, entityType, '', preprocessedQuery),
|
||||||
},
|
},
|
||||||
fetchPolicy: 'cache-first',
|
fetchPolicy: 'cache-first',
|
||||||
});
|
});
|
||||||
@ -89,6 +63,9 @@ export default function useStructuredProperties(query: string | undefined) {
|
|||||||
((data?.searchAcrossEntities?.searchResults ?? [])
|
((data?.searchAcrossEntities?.searchResults ?? [])
|
||||||
.map((result) => result.entity)
|
.map((result) => result.entity)
|
||||||
.filter(isStructuredProperty)
|
.filter(isStructuredProperty)
|
||||||
|
.filter((property) =>
|
||||||
|
SUPPORTED_STRUCTURED_PROPERTY_VALUE_TYPES.includes(property.definition.valueType.urn),
|
||||||
|
)
|
||||||
?.map((structuredProperty) => ({
|
?.map((structuredProperty) => ({
|
||||||
key: structuredProperty.urn,
|
key: structuredProperty.urn,
|
||||||
name: structuredProperty.definition.displayName ?? '',
|
name: structuredProperty.definition.displayName ?? '',
|
||||||
|
|||||||
@ -283,3 +283,27 @@ export const getDisplayNameFilter = (displayNameQuery: string) => {
|
|||||||
export function isStructuredProperty(entity?: Entity | null | undefined): entity is StructuredPropertyEntity {
|
export function isStructuredProperty(entity?: Entity | null | undefined): entity is StructuredPropertyEntity {
|
||||||
return !!entity && entity.type === EntityType.StructuredProperty;
|
return !!entity && entity.type === EntityType.StructuredProperty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getStructuredPropertiesSearchInputs(
|
||||||
|
entityRegistry: EntityRegistry,
|
||||||
|
entityType: EntityType,
|
||||||
|
fieldUrn?: string,
|
||||||
|
nameQuery?: string,
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
types: [EntityType.StructuredProperty],
|
||||||
|
query: '*',
|
||||||
|
start: 0,
|
||||||
|
count: 100,
|
||||||
|
searchFlags: { skipCache: true },
|
||||||
|
orFilters: [
|
||||||
|
{
|
||||||
|
and: [
|
||||||
|
getEntityTypesPropertyFilter(entityRegistry, !!fieldUrn, entityType),
|
||||||
|
getNotHiddenPropertyFilter(),
|
||||||
|
...(nameQuery ? [getDisplayNameFilter(nameQuery)] : []),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|||||||
@ -24,9 +24,6 @@ record StructuredPropertyDefinition {
|
|||||||
* The value type of the property. Must be a dataType.
|
* The value type of the property. Must be a dataType.
|
||||||
* e.g. To indicate that the property is of type DATE, use urn:li:dataType:datahub.date
|
* e.g. To indicate that the property is of type DATE, use urn:li:dataType:datahub.date
|
||||||
*/
|
*/
|
||||||
@Searchable = {
|
|
||||||
"fieldType": "URN"
|
|
||||||
}
|
|
||||||
@UrnValidation = {
|
@UrnValidation = {
|
||||||
"exist": true,
|
"exist": true,
|
||||||
"strict": true,
|
"strict": true,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user