fix(ingestion): fix group avatar (changes from SaaS) (#13772)

This commit is contained in:
v-tarasevich-blitz-brain 2025-06-30 19:36:54 +03:00 committed by GitHub
parent e5ef9a0f3a
commit f13fb828d7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 54 additions and 35 deletions

View File

@ -3,6 +3,7 @@ import React, { useState } from 'react';
import { AvatarImage, AvatarImageWrapper, AvatarText, Container } from '@components/components/Avatar/components';
import { AvatarProps } from '@components/components/Avatar/types';
import getAvatarColor, { getNameInitials } from '@components/components/Avatar/utils';
import { AvatarType } from '@components/components/AvatarStack/types';
import { Icon } from '@components/components/Icon';
export const avatarDefaults: AvatarProps = {
@ -10,7 +11,7 @@ export const avatarDefaults: AvatarProps = {
size: 'default',
showInPill: false,
isOutlined: false,
isGroup: false,
type: AvatarType.user,
};
export const Avatar = ({
@ -18,30 +19,27 @@ export const Avatar = ({
imageUrl,
size = avatarDefaults.size,
onClick,
type = avatarDefaults.type,
showInPill = avatarDefaults.showInPill,
isOutlined = avatarDefaults.isOutlined,
isGroup = avatarDefaults.isGroup,
}: AvatarProps) => {
const [hasError, setHasError] = useState(false);
return (
<Container onClick={onClick} $hasOnClick={!!onClick} $showInPill={showInPill}>
{(!isGroup || imageUrl) && (
<AvatarImageWrapper
$color={getAvatarColor(name)}
$size={size}
$isOutlined={isOutlined}
$hasImage={!!imageUrl}
>
{(type === AvatarType.user || imageUrl) && (
<AvatarImageWrapper $color={getAvatarColor(name)} $size={size} $isOutlined={isOutlined}>
{!hasError && imageUrl ? (
<AvatarImage src={imageUrl} onError={() => setHasError(true)} />
) : (
!isGroup && getNameInitials(name)
type === AvatarType.user && getNameInitials(name)
)}
</AvatarImageWrapper>
)}
{isGroup && !imageUrl && (
<Icon icon="UsersThree" source="phosphor" variant="filled" color="gray" size="lg" />
{type === AvatarType.group && !imageUrl && (
<AvatarImageWrapper $color={getAvatarColor(name)} $size={size} $isOutlined={isOutlined}>
<Icon icon="UsersThree" source="phosphor" variant="filled" size="lg" />
</AvatarImageWrapper>
)}
{showInPill && <AvatarText $size={size}>{name}</AvatarText>}
</Container>

View File

@ -26,17 +26,17 @@ export const AvatarImageWrapper = styled.div<{
$color: string;
$size?: AvatarSizeOptions;
$isOutlined?: boolean;
$hasImage?: boolean;
}>`
${(props) => getAvatarSizes(props.$size)}
position: relative;
border-radius: 50%;
color: ${(props) => props.$color};
border: ${(props) => props.$isOutlined && `1px solid ${colors.gray[1800]}`};
display: flex;
align-items: center;
justify-content: center;
${(props) => !props.$hasImage && getAvatarColorStyles(props.$color)}
${(props) => getAvatarColorStyles(props.$color)}
`;
export const AvatarImage = styled.img`

View File

@ -1,3 +1,5 @@
import { AvatarType } from '@components/components/AvatarStack/types';
import { AvatarSizeOptions } from '@src/alchemy-components/theme/config';
export interface AvatarProps {
@ -7,5 +9,5 @@ export interface AvatarProps {
size?: AvatarSizeOptions;
showInPill?: boolean;
isOutlined?: boolean;
isGroup?: boolean;
type?: AvatarType;
}

View File

@ -1,5 +1,9 @@
import { AvatarType } from '@components/components/AvatarStack/types';
import { colors } from '@src/alchemy-components/theme';
import { EntityType } from '@types';
export const getNameInitials = (userName: string) => {
if (!userName) return '';
const names = userName.trim().split(/[\s']+/); // Split by spaces or apostrophes
@ -63,3 +67,13 @@ export const getAvatarNameSizes = (size) => {
if (size === 'md') return '14px';
return '12px';
};
export const mapEntityTypeToAvatarType = (entityType: EntityType): AvatarType => {
if (entityType === EntityType.CorpGroup) return AvatarType.group;
return AvatarType.user;
};
export const mapAvatarTypeToEntityType = (avatarType: AvatarType): EntityType => {
if (avatarType === AvatarType.group) return EntityType.CorpGroup;
return EntityType.CorpUser;
};

View File

@ -18,7 +18,7 @@ export const AvatarStack = ({ avatars, size = 'md', showRemainingNumber = true,
const remainingNumber = avatars.length - maxToShow;
const renderAvatarStack = avatars?.slice(0, maxToShow).map((avatar: AvatarItemProps) => (
<AvatarContainer key={avatar.name}>
<Avatar size={size} isOutlined imageUrl={avatar.imageUrl} name={avatar.name} />
<Avatar size={size} isOutlined imageUrl={avatar.imageUrl} name={avatar.name} type={avatar.type} />
</AvatarContainer>
));
return (

View File

@ -4,13 +4,11 @@ import styled from 'styled-components';
import { AvatarStack } from '@components/components/AvatarStack/AvatarStack';
import HoverSectionContent from '@components/components/AvatarStack/HoverSectionContent';
import { AvatarStackProps } from '@components/components/AvatarStack/types';
import { AvatarStackProps, AvatarType } from '@components/components/AvatarStack/types';
import EntityRegistry from '@app/entityV2/EntityRegistry';
import StopPropagationWrapper from '@app/sharedV2/StopPropagationWrapper';
import { EntityType } from '@types';
const HeaderContainer = styled.div`
display: flex;
gap: 4px;
@ -27,8 +25,8 @@ const AvatarStackWithHover = ({
maxToShow = 4,
entityRegistry,
}: Props) => {
const users = avatars.filter((avatar) => avatar.type === EntityType.CorpUser);
const groups = avatars.filter((avatar) => avatar.type === EntityType.CorpGroup);
const users = avatars.filter((avatar) => avatar.type === AvatarType.user);
const groups = avatars.filter((avatar) => avatar.type === AvatarType.group);
const renderTitle = (headerText, count) => (
<HeaderContainer>
@ -68,7 +66,7 @@ const AvatarStackWithHover = ({
avatars={groups}
entityRegistry={entityRegistry}
size={size}
isGroup
type={AvatarType.group}
/>
),
},

View File

@ -3,10 +3,12 @@ import React, { useState } from 'react';
import { Link } from 'react-router-dom';
import styled from 'styled-components';
import { AvatarItemProps } from '@components/components/AvatarStack/types';
import { mapAvatarTypeToEntityType } from '@components/components/Avatar/utils';
import { AvatarItemProps, AvatarType } from '@components/components/AvatarStack/types';
import { AvatarSizeOptions } from '@components/theme/config';
import EntityRegistry from '@app/entityV2/EntityRegistry';
import isPresent from '@app/utils/isPresent';
const PillsContainer = styled.div`
display: flex;
@ -19,10 +21,10 @@ interface Props {
entityRegistry: EntityRegistry;
size?: AvatarSizeOptions;
maxVisible?: number;
isGroup?: boolean;
type?: AvatarType;
}
const HoverSectionContent = ({ avatars, entityRegistry, size, maxVisible = 4, isGroup }: Props) => {
const HoverSectionContent = ({ avatars, entityRegistry, size, maxVisible = 4, type }: Props) => {
const [expanded, setExpanded] = useState(false);
const visibleAvatars = expanded ? avatars : avatars.slice(0, maxVisible);
@ -39,15 +41,17 @@ const HoverSectionContent = ({ avatars, entityRegistry, size, maxVisible = 4, is
isOutlined
imageUrl={user.imageUrl}
name={user.name}
isGroup={isGroup}
type={type}
/>
);
return (
<>
{user.type && user.urn ? (
<Link to={entityRegistry.getEntityUrl(user.type, user.urn)}>{userAvatar}</Link>
{isPresent(user.type) && user.urn ? (
<Link to={entityRegistry.getEntityUrl(mapAvatarTypeToEntityType(user.type), user.urn)}>
{userAvatar}
</Link>
) : (
{ userAvatar }
userAvatar
)}
</>
);

View File

@ -1,12 +1,14 @@
import { AvatarSizeOptions } from '@src/alchemy-components/theme/config';
import { EntityType } from '@types';
export enum AvatarType {
user,
group,
}
export interface AvatarItemProps {
name: string;
imageUrl?: string | null;
type?: EntityType;
urn?: string;
type?: AvatarType;
}
export type AvatarStackProps = {

View File

@ -5,6 +5,7 @@ import React from 'react';
import { Link } from 'react-router-dom';
import styled from 'styled-components/macro';
import { mapEntityTypeToAvatarType } from '@components/components/Avatar/utils';
import AvatarStackWithHover from '@components/components/AvatarStack/AvatarStackWithHover';
import EntityRegistry from '@app/entityV2/EntityRegistry';
@ -14,7 +15,7 @@ import useGetSourceLogoUrl from '@app/ingestV2/source/builder/useGetSourceLogoUr
import { HoverEntityTooltip } from '@app/recommendations/renderer/component/HoverEntityTooltip';
import { capitalizeFirstLetter } from '@app/shared/textUtil';
import { EntityType, Owner } from '@types';
import { Owner } from '@types';
const PreviewImage = styled(Image)`
max-height: 20px;
@ -119,7 +120,7 @@ export function OwnerColumn({ owners, entityRegistry }: { owners: Owner[]; entit
return {
name: entityRegistry.getDisplayName(owner.owner.type, owner.owner),
imageUrl: owner.owner.editableProperties?.pictureLink,
type: owner.owner.type,
type: mapEntityTypeToAvatarType(owner.owner.type),
urn: owner.owner.urn,
};
});
@ -141,7 +142,7 @@ export function OwnerColumn({ owners, entityRegistry }: { owners: Owner[]; entit
name={entityRegistry.getDisplayName(singleOwner.type, singleOwner)}
imageUrl={singleOwner.editableProperties?.pictureLink}
showInPill
isGroup={singleOwner.type === EntityType.CorpGroup}
type={mapEntityTypeToAvatarType(singleOwner.type)}
/>
</Link>
</HoverEntityTooltip>