refactor: update avatar sizes in groups, users and members (#17230)

We updated the template and workspace avatars to be "lg" so to keep it
consistent we have to do the same for the other avatars too.
This commit is contained in:
Bruno Quaresma
2025-04-04 10:09:37 -03:00
committed by GitHub
parent 3bfafe3b43
commit 510bc37cbc
10 changed files with 110 additions and 80 deletions
+3 -3
View File
@@ -22,9 +22,9 @@ const avatarVariants = cva(
{
variants: {
size: {
lg: "h-[--avatar-lg] w-[--avatar-lg] rounded-[6px] text-sm font-medium",
md: "h-[--avatar-default] w-[--avatar-default] text-2xs",
sm: "h-[--avatar-sm] w-[--avatar-sm] text-[8px]",
lg: "size-[--avatar-lg] rounded-[6px] text-sm font-medium",
md: "size-[--avatar-default] text-2xs",
sm: "size-[--avatar-sm] text-[8px]",
},
variant: {
default: null,
+4 -4
View File
@@ -1,6 +1,4 @@
import { useTheme } from "@emotion/react";
import { Avatar } from "components/Avatar/Avatar";
import { Stack } from "components/Stack/Stack";
import type { FC, ReactNode } from "react";
export interface AvatarDataProps {
@@ -26,10 +24,10 @@ export const AvatarData: FC<AvatarDataProps> = ({
imgFallbackText,
avatar,
}) => {
const theme = useTheme();
if (!avatar) {
avatar = (
<Avatar
size="lg"
src={src}
fallback={(typeof title === "string" ? title : imgFallbackText) || "-"}
/>
@@ -41,7 +39,9 @@ export const AvatarData: FC<AvatarDataProps> = ({
{avatar}
<div className="flex flex-col w-full">
<span className="text-sm font-semibold">{title}</span>
<span className="text-sm font-semibold text-content-primary">
{title}
</span>
{subtitle && (
<span className="text-content-secondary text-xs font-medium">
{subtitle}
@@ -5,7 +5,7 @@ import type { FC } from "react";
export const AvatarDataSkeleton: FC = () => {
return (
<div className="flex items-center gap-3 w-full">
<Skeleton variant="rectangular" className="size-10 rounded-sm" />
<Skeleton variant="rectangular" className="size-10 rounded-sm shrink-0" />
<div className="flex flex-col w-full">
<Skeleton variant="text" width={100} />
+8 -2
View File
@@ -2,6 +2,7 @@ import { useTheme } from "@emotion/react";
import dayjs from "dayjs";
import relativeTime from "dayjs/plugin/relativeTime";
import type { FC, HTMLAttributes } from "react";
import { cn } from "utils/cn";
dayjs.extend(relativeTime);
@@ -11,7 +12,7 @@ interface LastSeenProps
"data-chromatic"?: string; // prevents a type error in the stories
}
export const LastSeen: FC<LastSeenProps> = ({ at, ...attrs }) => {
export const LastSeen: FC<LastSeenProps> = ({ at, className, ...attrs }) => {
const theme = useTheme();
const t = dayjs(at);
const now = dayjs();
@@ -35,7 +36,12 @@ export const LastSeen: FC<LastSeenProps> = ({ at, ...attrs }) => {
}
return (
<span data-chromatic="ignore" css={{ color }} {...attrs}>
<span
data-chromatic="ignore"
css={{ color }}
{...attrs}
className={cn(["whitespace-nowrap", className])}
>
{message}
</span>
);
+2 -2
View File
@@ -82,7 +82,7 @@ export const TableHead = React.forwardRef<
<th
ref={ref}
className={cn(
"py-2 px-4 text-left align-middle font-semibold",
"p-3 text-left align-middle font-semibold",
"[&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
className,
)}
@@ -98,7 +98,7 @@ export const TableCell = React.forwardRef<
ref={ref}
className={cn(
"border-0 border-t border-border border-solid",
"py-2 px-4 align-middle [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
"p-3 align-middle [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
className,
)}
{...props}
+7 -1
View File
@@ -310,7 +310,13 @@ const GroupMemberRow: FC<GroupMemberRowProps> = ({
<TableRow key={member.id}>
<TableCell width="59%">
<AvatarData
avatar={<Avatar fallback={member.username} src={member.avatar_url} />}
avatar={
<Avatar
size="lg"
fallback={member.username}
src={member.avatar_url}
/>
}
title={member.username}
subtitle={member.email}
/>
+23 -15
View File
@@ -1,12 +1,12 @@
import type { Interpolation, Theme } from "@emotion/react";
import AddOutlined from "@mui/icons-material/AddOutlined";
import KeyboardArrowRight from "@mui/icons-material/KeyboardArrowRight";
import AvatarGroup from "@mui/material/AvatarGroup";
import Skeleton from "@mui/material/Skeleton";
import type { Group } from "api/typesGenerated";
import { Avatar } from "components/Avatar/Avatar";
import { AvatarData } from "components/Avatar/AvatarData";
import { AvatarDataSkeleton } from "components/Avatar/AvatarDataSkeleton";
import { Badge } from "components/Badge/Badge";
import { Button } from "components/Button/Button";
import { ChooseOne, Cond } from "components/Conditionals/ChooseOne";
import { EmptyState } from "components/EmptyState/EmptyState";
@@ -115,6 +115,8 @@ const GroupRow: FC<GroupRowProps> = ({ group }) => {
const rowProps = useClickableTableRow({
onClick: () => navigate(group.name),
});
const memberAvatars = group.members.slice(0, 5);
const remainingAvatars = group.members.length - memberAvatars.length;
return (
<TableRow data-testid={`group-${group.id}`} {...rowProps}>
@@ -122,6 +124,8 @@ const GroupRow: FC<GroupRowProps> = ({ group }) => {
<AvatarData
avatar={
<Avatar
size="lg"
variant="icon"
fallback={group.display_name || group.name}
src={group.avatar_url}
/>
@@ -132,20 +136,24 @@ const GroupRow: FC<GroupRowProps> = ({ group }) => {
</TableCell>
<TableCell>
{group.members.length === 0 && "-"}
<AvatarGroup
max={10}
total={group.members.length}
css={{ justifyContent: "flex-end", gap: 8 }}
>
{group.members.map((member) => (
<Avatar
key={member.username}
fallback={member.username}
src={member.avatar_url}
/>
))}
</AvatarGroup>
{group.members.length > 0 ? (
<div className="flex items-center gap-2">
{memberAvatars.map((member) => (
<Avatar
key={member.username}
fallback={member.username}
src={member.avatar_url}
/>
))}
{remainingAvatars > 0 && (
<Badge className="h-[--avatar-default]">
+{remainingAvatars}
</Badge>
)}
</div>
) : (
"-"
)}
</TableCell>
<TableCell>
@@ -11,6 +11,7 @@ import { ErrorAlert } from "components/Alert/ErrorAlert";
import { Avatar } from "components/Avatar/Avatar";
import { AvatarData } from "components/Avatar/AvatarData";
import { displayError, displaySuccess } from "components/GlobalSnackbar/utils";
import { Loader } from "components/Loader/Loader";
import {
MoreMenu,
MoreMenuContent,
@@ -32,6 +33,7 @@ import {
TableHeader,
TableRow,
} from "components/Table/Table";
import { TableLoader } from "components/TableLoader/TableLoader";
import { UserAutocomplete } from "components/UserAutocomplete/UserAutocomplete";
import type { PaginationResultInfo } from "hooks/usePaginatedQuery";
import { TriangleAlert } from "lucide-react";
@@ -125,58 +127,67 @@ export const OrganizationMembersPageView: FC<
</TableRow>
</TableHeader>
<TableBody>
{members?.map((member) => (
<TableRow key={member.user_id} className="align-baseline">
<TableCell>
<AvatarData
avatar={
<Avatar
fallback={member.username}
src={member.avatar_url}
/>
}
title={member.name || member.username}
subtitle={member.email}
{members ? (
members.map((member) => (
<TableRow key={member.user_id} className="align-baseline">
<TableCell>
<AvatarData
avatar={
<Avatar
fallback={member.username}
src={member.avatar_url}
size="lg"
/>
}
title={member.name || member.username}
subtitle={member.email}
/>
</TableCell>
<UserRoleCell
inheritedRoles={member.global_roles}
roles={member.roles}
allAvailableRoles={allAvailableRoles}
oidcRoleSyncEnabled={false}
isLoading={isUpdatingMemberRoles}
canEditUsers={canEditMembers}
onEditRoles={async (roles) => {
try {
await updateMemberRoles(member, roles);
displaySuccess("Roles updated successfully.");
} catch (error) {
displayError(
getErrorMessage(error, "Failed to update roles."),
);
}
}}
/>
</TableCell>
<UserRoleCell
inheritedRoles={member.global_roles}
roles={member.roles}
allAvailableRoles={allAvailableRoles}
oidcRoleSyncEnabled={false}
isLoading={isUpdatingMemberRoles}
canEditUsers={canEditMembers}
onEditRoles={async (roles) => {
try {
await updateMemberRoles(member, roles);
displaySuccess("Roles updated successfully.");
} catch (error) {
displayError(
getErrorMessage(error, "Failed to update roles."),
);
}
}}
/>
<UserGroupsCell userGroups={member.groups} />
<TableCell>
{member.user_id !== me.id && canEditMembers && (
<MoreMenu>
<MoreMenuTrigger>
<ThreeDotsButton />
</MoreMenuTrigger>
<MoreMenuContent>
<MoreMenuItem
danger
onClick={() => removeMember(member)}
>
Remove
</MoreMenuItem>
</MoreMenuContent>
</MoreMenu>
)}
<UserGroupsCell userGroups={member.groups} />
<TableCell>
{member.user_id !== me.id && canEditMembers && (
<MoreMenu>
<MoreMenuTrigger>
<ThreeDotsButton />
</MoreMenuTrigger>
<MoreMenuContent>
<MoreMenuItem
danger
onClick={() => removeMember(member)}
>
Remove
</MoreMenuItem>
</MoreMenuContent>
</MoreMenu>
)}
</TableCell>
</TableRow>
))
) : (
<TableRow>
<TableCell colSpan={999}>
<Loader />
</TableCell>
</TableRow>
))}
)}
</TableBody>
</Table>
</PaginationContainer>
@@ -258,6 +258,7 @@ export const TemplatePermissionsPageView: FC<
<AvatarData
avatar={
<Avatar
size="lg"
fallback={group.display_name || group.name}
src={group.avatar_url}
/>
@@ -87,9 +87,7 @@ export const UsersTableBody: FC<UsersTableBodyProps> = ({
<TableLoaderSkeleton>
<TableRowSkeleton>
<TableCell>
<div css={{ display: "flex", alignItems: "center", gap: 8 }}>
<AvatarDataSkeleton />
</div>
<AvatarDataSkeleton />
</TableCell>
<TableCell>