Issue-13594: Show database and schema. (#13856)

Co-authored-by: Maciek Rakowski <maciekrakowski@Macieks-MacBook-Pro.local>
Co-authored-by: Andrew Sikowitz <andrew.sikowitz@acryl.io>
This commit is contained in:
Maciek 2025-08-06 07:15:36 -07:00 committed by GitHub
parent f04244fd69
commit 0242777c4b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 154 additions and 23 deletions

View File

@ -4352,3 +4352,25 @@ export const mockFineGrainedLineages1: GenericEntityProperties = {
}, },
], ],
}; };
export const useEntityDataFunc = () => {
const value = {
entityData: {
parentContainers: {
containers: [
{
properties: {
name: 'name1',
},
},
{
properties: {
name: 'name2',
},
},
],
},
},
};
return value;
};

View File

@ -0,0 +1,27 @@
import { render } from '@testing-library/react';
import React from 'react';
import LineageEntityView from '@app/lineage/manage/LineageEntityView';
import { dataset1 } from '@src/Mocks';
import { getTestEntityRegistry } from '@utils/test-utils/TestPageContainer';
const mockEntityRegistry = getTestEntityRegistry();
vi.mock('../../useEntityRegistry', () => ({
useEntityRegistry: () => mockEntityRegistry,
}));
vi.mock('@app/entity/shared/EntityContext', () => ({
useEntityData: () => {
return {};
},
}));
describe('LineageEntityViewEmpty', () => {
it('should render an entity properly in LineageEntityView if no containers', () => {
const { getByTestId, getByText } = render(<LineageEntityView entity={dataset1} />);
// expect platform logo, platform name, divider, entity type, and display name
expect(getByTestId('platform-logo')).toBeInTheDocument();
expect(getByText(dataset1.platform.name)).toBeInTheDocument();
expect(getByTestId('divider')).toBeInTheDocument();
expect(getByText('Dataset')).toBeInTheDocument();
expect(getByText(dataset1.properties.name)).toBeInTheDocument();
});
});

View File

@ -2,7 +2,7 @@ import { render } from '@testing-library/react';
import React from 'react'; import React from 'react';
import LineageEntityView from '@app/lineage/manage/LineageEntityView'; import LineageEntityView from '@app/lineage/manage/LineageEntityView';
import { dataset1 } from '@src/Mocks'; import { dataset1, useEntityDataFunc } from '@src/Mocks';
import { getTestEntityRegistry } from '@utils/test-utils/TestPageContainer'; import { getTestEntityRegistry } from '@utils/test-utils/TestPageContainer';
const mockEntityRegistry = getTestEntityRegistry(); const mockEntityRegistry = getTestEntityRegistry();
@ -10,10 +10,15 @@ vi.mock('../../useEntityRegistry', () => ({
useEntityRegistry: () => mockEntityRegistry, useEntityRegistry: () => mockEntityRegistry,
})); }));
vi.mock('@app/entity/shared/EntityContext', () => ({
useEntityData: () => {
return useEntityDataFunc();
},
}));
describe('LineageEntityView', () => { describe('LineageEntityView', () => {
it('should render an entity properly in LineageEntityView', () => { it('should render an entity properly in LineageEntityView', () => {
const { getByTestId, getByText } = render(<LineageEntityView entity={dataset1} />); const { getByTestId, getByText } = render(<LineageEntityView entity={dataset1} />);
// expect platform logo, platform name, divider, entity type, and display name // expect platform logo, platform name, divider, entity type, and display name
expect(getByTestId('platform-logo')).toBeInTheDocument(); expect(getByTestId('platform-logo')).toBeInTheDocument();
expect(getByText(dataset1.platform.name)).toBeInTheDocument(); expect(getByText(dataset1.platform.name)).toBeInTheDocument();
@ -25,18 +30,26 @@ describe('LineageEntityView', () => {
it('should render the subtype name if it exists and not the type name', () => { it('should render the subtype name if it exists and not the type name', () => {
const datasetWithSubtype = { ...dataset1, subTypes: { typeNames: ['view'] } }; const datasetWithSubtype = { ...dataset1, subTypes: { typeNames: ['view'] } };
const { getByText, queryByText } = render(<LineageEntityView entity={datasetWithSubtype} />); const { getByText, queryByText } = render(<LineageEntityView entity={datasetWithSubtype} />);
expect(queryByText('Dataset')).not.toBeInTheDocument(); expect(queryByText('Dataset')).not.toBeInTheDocument();
expect(getByText('View')).toBeInTheDocument(); expect(getByText('View')).toBeInTheDocument();
}); });
it('should not render a divider if there is no platform name', () => { it('should not render a divider if there is no platform name', () => {
vi.mock('@app/entity/shared/EntityContext', () => ({
useEntityData: () => {
return useEntityDataFunc();
},
}));
const datasetNoPlatformName = { const datasetNoPlatformName = {
...dataset1, ...dataset1,
platform: { ...dataset1.platform, name: '', properties: { displayName: '' } }, platform: { ...dataset1.platform, name: '', properties: { displayName: '' } },
}; };
const { queryByTestId } = render(<LineageEntityView entity={datasetNoPlatformName} />); const { queryByTestId } = render(<LineageEntityView entity={datasetNoPlatformName} />);
expect(queryByTestId('divider')).not.toBeInTheDocument(); expect(queryByTestId('divider')).not.toBeInTheDocument();
}); });
afterAll(() => {
vi.resetAllMocks();
});
}); });

View File

@ -0,0 +1,30 @@
import React from 'react';
import { StyledRightOutlined } from '@app/entity/shared/containers/profile/header/PlatformContent/ParentNodesView';
import { Container } from '@types';
export interface ContainerViewProps {
directContainer: Container | undefined | null;
remainingContainers: Container[] | undefined | null;
}
export function ContainerView({ directContainer, remainingContainers }: ContainerViewProps) {
return (
<>
{remainingContainers &&
remainingContainers.map((c) => (
<>
<StyledRightOutlined data-testid="right-arrow" />
<span>{c?.properties?.name}</span>
</>
))}
{directContainer && (
<>
<StyledRightOutlined data-testid="right-arrow" />
<span>{directContainer?.properties?.name}</span>
</>
)}
</>
);
}

View File

@ -3,14 +3,36 @@ import Text from 'antd/lib/typography/Text';
import React from 'react'; import React from 'react';
import styled from 'styled-components/macro'; import styled from 'styled-components/macro';
import { useEntityData } from '@app/entity/shared/EntityContext';
import { ANTD_GRAY, DEFAULT_SYSTEM_ACTOR_URNS } from '@app/entity/shared/constants'; import { ANTD_GRAY, DEFAULT_SYSTEM_ACTOR_URNS } from '@app/entity/shared/constants';
import { getPlatformName } from '@app/entity/shared/utils';
import { ContainerView } from '@app/lineage/manage/ContainerView';
import UserAvatar from '@app/lineage/manage/UserAvatar'; import UserAvatar from '@app/lineage/manage/UserAvatar';
import { useEntityRegistry } from '@app/useEntityRegistry'; import { useEntityRegistry } from '@app/useEntityRegistry';
import { CorpUser, Entity } from '@types'; import { CorpUser, Entity } from '@types';
const EntityItem = styled.div` const PlatformContent = styled.div<{ removeMargin?: boolean }>`
display: flex;
align-items: center;
font-size: 10px;
margin-left: 5px;
color: ${ANTD_GRAY[7]};
`;
const PlatformName = styled.span`
margin-left: 0px;
`;
const EntityItemOuter = styled.div`
border-bottom: 1px solid ${ANTD_GRAY[4]}; border-bottom: 1px solid ${ANTD_GRAY[4]};
display: block;
align-items: center;
padding: 12px 0;
justify-content: space-between;
`;
const EntityItem = styled.div`
display: flex; display: flex;
align-items: center; align-items: center;
padding: 12px 0; padding: 12px 0;
@ -45,12 +67,21 @@ interface Props {
export default function EntityEdge({ entity, removeEntity, createdActor, createdOn }: Props) { export default function EntityEdge({ entity, removeEntity, createdActor, createdOn }: Props) {
const entityRegistry = useEntityRegistry(); const entityRegistry = useEntityRegistry();
const { entityData } = useEntityData();
const genericProps = entityRegistry.getGenericEntityProperties(entity.type, entity); const genericProps = entityRegistry.getGenericEntityProperties(entity.type, entity);
const platformLogoUrl = genericProps?.platform?.properties?.logoUrl; const platformLogoUrl = genericProps?.platform?.properties?.logoUrl;
const shouldDisplayAvatar = const shouldDisplayAvatar =
createdActor && !DEFAULT_SYSTEM_ACTOR_URNS.includes(createdActor.urn) && createdActor.properties !== null; createdActor && !DEFAULT_SYSTEM_ACTOR_URNS.includes(createdActor.urn) && createdActor.properties !== null;
const containers = entityData?.parentContainers?.containers;
const remainingContainers = containers?.slice(1);
const directContainer = containers ? containers[0] : null;
const platformName = getPlatformName(genericProps);
return ( return (
<EntityItemOuter>
<PlatformContent>
<PlatformName>{platformName}</PlatformName>
<ContainerView remainingContainers={remainingContainers} directContainer={directContainer} />
</PlatformContent>
<EntityItem data-testid="lineage-entity-item"> <EntityItem data-testid="lineage-entity-item">
<NameAndLogoWrapper> <NameAndLogoWrapper>
{platformLogoUrl && <PlatformLogo src={platformLogoUrl} alt="platform logo" />}{' '} {platformLogoUrl && <PlatformLogo src={platformLogoUrl} alt="platform logo" />}{' '}
@ -63,5 +94,6 @@ export default function EntityEdge({ entity, removeEntity, createdActor, created
<StyledClose onClick={() => removeEntity(entity)} /> <StyledClose onClick={() => removeEntity(entity)} />
</span> </span>
</EntityItem> </EntityItem>
</EntityItemOuter>
); );
} }

View File

@ -2,8 +2,10 @@ import { Divider } from 'antd';
import React from 'react'; import React from 'react';
import styled from 'styled-components/macro'; import styled from 'styled-components/macro';
import { useEntityData } from '@app/entity/shared/EntityContext';
import { ANTD_GRAY } from '@app/entity/shared/constants'; import { ANTD_GRAY } from '@app/entity/shared/constants';
import { getPlatformName } from '@app/entity/shared/utils'; import { getPlatformName } from '@app/entity/shared/utils';
import { ContainerView } from '@app/lineage/manage/ContainerView';
import { capitalizeFirstLetterOnly } from '@app/shared/textUtil'; import { capitalizeFirstLetterOnly } from '@app/shared/textUtil';
import { useEntityRegistry } from '@app/useEntityRegistry'; import { useEntityRegistry } from '@app/useEntityRegistry';
@ -44,22 +46,27 @@ interface Props {
export default function LineageEntityView({ entity, displaySearchResult }: Props) { export default function LineageEntityView({ entity, displaySearchResult }: Props) {
const entityRegistry = useEntityRegistry(); const entityRegistry = useEntityRegistry();
const genericProps = entityRegistry.getGenericEntityProperties(entity.type, entity); const genericProps = entityRegistry.getGenericEntityProperties(entity.type, entity);
const { entityData } = useEntityData();
const platformLogoUrl = genericProps?.platform?.properties?.logoUrl; const platformLogoUrl = genericProps?.platform?.properties?.logoUrl;
const platformName = getPlatformName(genericProps); const platformName = getPlatformName(genericProps);
const containers = entityData?.parentContainers?.containers;
const remainingContainers = containers?.slice(1);
const directContainer = containers ? containers[0] : null;
return ( return (
<EntityWrapper shrinkPadding={displaySearchResult}> <EntityWrapper shrinkPadding={displaySearchResult}>
<PlatformContent removeMargin={displaySearchResult}> <PlatformContent removeMargin={displaySearchResult}>
{platformLogoUrl && (
<PlatformLogo src={platformLogoUrl} alt="platform logo" data-testid="platform-logo" />
)}
<span>{platformName}</span>
{platformName && <StyledDivider type="vertical" data-testid="divider" />}
<span> <span>
{capitalizeFirstLetterOnly(genericProps?.subTypes?.typeNames?.[0]) || {capitalizeFirstLetterOnly(genericProps?.subTypes?.typeNames?.[0]) ||
entityRegistry.getEntityName(entity.type)} entityRegistry.getEntityName(entity.type)}
</span> </span>
{platformName && <StyledDivider type="vertical" data-testid="divider" />}
{platformLogoUrl && (
<PlatformLogo src={platformLogoUrl} alt="platform logo" data-testid="platform-logo" />
)}
<span>{platformName}</span>
<ContainerView remainingContainers={remainingContainers} directContainer={directContainer} />
</PlatformContent> </PlatformContent>
<EntityName shrinkSize={displaySearchResult}> <EntityName shrinkSize={displaySearchResult}>
{entityRegistry.getDisplayName(entity.type, entity)} {entityRegistry.getDisplayName(entity.type, entity)}