Skip to content

Commit 91ebf24

Browse files
committed
refactor: update avatar sizes in groups, users and members
1 parent e8b7ce8 commit 91ebf24

File tree

9 files changed

+109
-80
lines changed

9 files changed

+109
-80
lines changed

site/src/components/Avatar/Avatar.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ const avatarVariants = cva(
2222
{
2323
variants: {
2424
size: {
25-
lg: "h-[--avatar-lg] w-[--avatar-lg] rounded-[6px] text-sm font-medium",
26-
md: "h-[--avatar-default] w-[--avatar-default] text-2xs",
27-
sm: "h-[--avatar-sm] w-[--avatar-sm] text-[8px]",
25+
lg: "size-[--avatar-lg] rounded-[6px] text-sm font-medium",
26+
md: "size-[--avatar-default] text-2xs",
27+
sm: "size-[--avatar-sm] text-[8px]",
2828
},
2929
variant: {
3030
default: null,

site/src/components/Avatar/AvatarData.tsx

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
import { useTheme } from "@emotion/react";
21
import { Avatar } from "components/Avatar/Avatar";
3-
import { Stack } from "components/Stack/Stack";
42
import type { FC, ReactNode } from "react";
53

64
export interface AvatarDataProps {
@@ -26,10 +24,10 @@ export const AvatarData: FC<AvatarDataProps> = ({
2624
imgFallbackText,
2725
avatar,
2826
}) => {
29-
const theme = useTheme();
3027
if (!avatar) {
3128
avatar = (
3229
<Avatar
30+
size="lg"
3331
src={src}
3432
fallback={(typeof title === "string" ? title : imgFallbackText) || "-"}
3533
/>
@@ -41,7 +39,9 @@ export const AvatarData: FC<AvatarDataProps> = ({
4139
{avatar}
4240

4341
<div className="flex flex-col w-full">
44-
<span className="text-sm font-semibold">{title}</span>
42+
<span className="text-sm font-semibold text-content-primary">
43+
{title}
44+
</span>
4545
{subtitle && (
4646
<span className="text-content-secondary text-xs font-medium">
4747
{subtitle}

site/src/components/Avatar/AvatarDataSkeleton.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import type { FC } from "react";
55
export const AvatarDataSkeleton: FC = () => {
66
return (
77
<div className="flex items-center gap-3 w-full">
8-
<Skeleton variant="rectangular" className="size-10 rounded-sm" />
8+
<Skeleton variant="rectangular" className="size-10 rounded-sm shrink-0" />
99

1010
<div className="flex flex-col w-full">
1111
<Skeleton variant="text" width={100} />

site/src/components/LastSeen/LastSeen.tsx

+8-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { useTheme } from "@emotion/react";
22
import dayjs from "dayjs";
33
import relativeTime from "dayjs/plugin/relativeTime";
44
import type { FC, HTMLAttributes } from "react";
5+
import { cn } from "utils/cn";
56

67
dayjs.extend(relativeTime);
78

@@ -11,7 +12,7 @@ interface LastSeenProps
1112
"data-chromatic"?: string; // prevents a type error in the stories
1213
}
1314

14-
export const LastSeen: FC<LastSeenProps> = ({ at, ...attrs }) => {
15+
export const LastSeen: FC<LastSeenProps> = ({ at, className, ...attrs }) => {
1516
const theme = useTheme();
1617
const t = dayjs(at);
1718
const now = dayjs();
@@ -35,7 +36,12 @@ export const LastSeen: FC<LastSeenProps> = ({ at, ...attrs }) => {
3536
}
3637

3738
return (
38-
<span data-chromatic="ignore" css={{ color }} {...attrs}>
39+
<span
40+
data-chromatic="ignore"
41+
css={{ color }}
42+
{...attrs}
43+
className={cn(["whitespace-nowrap", className])}
44+
>
3945
{message}
4046
</span>
4147
);

site/src/components/Table/Table.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ export const TableHead = React.forwardRef<
8282
<th
8383
ref={ref}
8484
className={cn(
85-
"py-2 px-4 text-left align-middle font-semibold",
85+
"p-3 text-left align-middle font-semibold",
8686
"[&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
8787
className,
8888
)}
@@ -98,7 +98,7 @@ export const TableCell = React.forwardRef<
9898
ref={ref}
9999
className={cn(
100100
"border-0 border-t border-border border-solid",
101-
"py-2 px-4 align-middle [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
101+
"p-3 align-middle [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
102102
className,
103103
)}
104104
{...props}

site/src/pages/GroupsPage/GroupPage.tsx

+7-1
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,13 @@ const GroupMemberRow: FC<GroupMemberRowProps> = ({
310310
<TableRow key={member.id}>
311311
<TableCell width="59%">
312312
<AvatarData
313-
avatar={<Avatar fallback={member.username} src={member.avatar_url} />}
313+
avatar={
314+
<Avatar
315+
size="lg"
316+
fallback={member.username}
317+
src={member.avatar_url}
318+
/>
319+
}
314320
title={member.username}
315321
subtitle={member.email}
316322
/>

site/src/pages/GroupsPage/GroupsPageView.tsx

+23-15
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import type { Interpolation, Theme } from "@emotion/react";
22
import AddOutlined from "@mui/icons-material/AddOutlined";
33
import KeyboardArrowRight from "@mui/icons-material/KeyboardArrowRight";
4-
import AvatarGroup from "@mui/material/AvatarGroup";
54
import Skeleton from "@mui/material/Skeleton";
65
import type { Group } from "api/typesGenerated";
76
import { Avatar } from "components/Avatar/Avatar";
87
import { AvatarData } from "components/Avatar/AvatarData";
98
import { AvatarDataSkeleton } from "components/Avatar/AvatarDataSkeleton";
9+
import { Badge } from "components/Badge/Badge";
1010
import { Button } from "components/Button/Button";
1111
import { ChooseOne, Cond } from "components/Conditionals/ChooseOne";
1212
import { EmptyState } from "components/EmptyState/EmptyState";
@@ -115,13 +115,17 @@ const GroupRow: FC<GroupRowProps> = ({ group }) => {
115115
const rowProps = useClickableTableRow({
116116
onClick: () => navigate(group.name),
117117
});
118+
const memberAvatars = group.members.slice(0, 5);
119+
const remainingAvatars = group.members.length - memberAvatars.length;
118120

119121
return (
120122
<TableRow data-testid={`group-${group.id}`} {...rowProps}>
121123
<TableCell>
122124
<AvatarData
123125
avatar={
124126
<Avatar
127+
size="lg"
128+
variant="icon"
125129
fallback={group.display_name || group.name}
126130
src={group.avatar_url}
127131
/>
@@ -132,20 +136,24 @@ const GroupRow: FC<GroupRowProps> = ({ group }) => {
132136
</TableCell>
133137

134138
<TableCell>
135-
{group.members.length === 0 && "-"}
136-
<AvatarGroup
137-
max={10}
138-
total={group.members.length}
139-
css={{ justifyContent: "flex-end", gap: 8 }}
140-
>
141-
{group.members.map((member) => (
142-
<Avatar
143-
key={member.username}
144-
fallback={member.username}
145-
src={member.avatar_url}
146-
/>
147-
))}
148-
</AvatarGroup>
139+
{group.members.length > 0 ? (
140+
<div className="flex items-center gap-2">
141+
{memberAvatars.map((member) => (
142+
<Avatar
143+
key={member.username}
144+
fallback={member.username}
145+
src={member.avatar_url}
146+
/>
147+
))}
148+
{remainingAvatars > 0 && (
149+
<Badge className="h-[--avatar-default]">
150+
+{remainingAvatars}
151+
</Badge>
152+
)}
153+
</div>
154+
) : (
155+
"-"
156+
)}
149157
</TableCell>
150158

151159
<TableCell>

site/src/pages/OrganizationSettingsPage/OrganizationMembersPageView.tsx

+60-49
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ import { UserGroupsCell } from "pages/UsersPage/UsersTable/UserGroupsCell";
3939
import { type FC, useState } from "react";
4040
import { TableColumnHelpTooltip } from "./UserTable/TableColumnHelpTooltip";
4141
import { UserRoleCell } from "./UserTable/UserRoleCell";
42+
import { TableLoader } from "components/TableLoader/TableLoader";
43+
import { Loader } from "components/Loader/Loader";
4244

4345
interface OrganizationMembersPageViewProps {
4446
allAvailableRoles: readonly SlimRole[] | undefined;
@@ -125,58 +127,67 @@ export const OrganizationMembersPageView: FC<
125127
</TableRow>
126128
</TableHeader>
127129
<TableBody>
128-
{members?.map((member) => (
129-
<TableRow key={member.user_id} className="align-baseline">
130-
<TableCell>
131-
<AvatarData
132-
avatar={
133-
<Avatar
134-
fallback={member.username}
135-
src={member.avatar_url}
136-
/>
137-
}
138-
title={member.name || member.username}
139-
subtitle={member.email}
130+
{members ? (
131+
members.map((member) => (
132+
<TableRow key={member.user_id} className="align-baseline">
133+
<TableCell>
134+
<AvatarData
135+
avatar={
136+
<Avatar
137+
fallback={member.username}
138+
src={member.avatar_url}
139+
size="lg"
140+
/>
141+
}
142+
title={member.name || member.username}
143+
subtitle={member.email}
144+
/>
145+
</TableCell>
146+
<UserRoleCell
147+
inheritedRoles={member.global_roles}
148+
roles={member.roles}
149+
allAvailableRoles={allAvailableRoles}
150+
oidcRoleSyncEnabled={false}
151+
isLoading={isUpdatingMemberRoles}
152+
canEditUsers={canEditMembers}
153+
onEditRoles={async (roles) => {
154+
try {
155+
await updateMemberRoles(member, roles);
156+
displaySuccess("Roles updated successfully.");
157+
} catch (error) {
158+
displayError(
159+
getErrorMessage(error, "Failed to update roles."),
160+
);
161+
}
162+
}}
140163
/>
141-
</TableCell>
142-
<UserRoleCell
143-
inheritedRoles={member.global_roles}
144-
roles={member.roles}
145-
allAvailableRoles={allAvailableRoles}
146-
oidcRoleSyncEnabled={false}
147-
isLoading={isUpdatingMemberRoles}
148-
canEditUsers={canEditMembers}
149-
onEditRoles={async (roles) => {
150-
try {
151-
await updateMemberRoles(member, roles);
152-
displaySuccess("Roles updated successfully.");
153-
} catch (error) {
154-
displayError(
155-
getErrorMessage(error, "Failed to update roles."),
156-
);
157-
}
158-
}}
159-
/>
160-
<UserGroupsCell userGroups={member.groups} />
161-
<TableCell>
162-
{member.user_id !== me.id && canEditMembers && (
163-
<MoreMenu>
164-
<MoreMenuTrigger>
165-
<ThreeDotsButton />
166-
</MoreMenuTrigger>
167-
<MoreMenuContent>
168-
<MoreMenuItem
169-
danger
170-
onClick={() => removeMember(member)}
171-
>
172-
Remove
173-
</MoreMenuItem>
174-
</MoreMenuContent>
175-
</MoreMenu>
176-
)}
164+
<UserGroupsCell userGroups={member.groups} />
165+
<TableCell>
166+
{member.user_id !== me.id && canEditMembers && (
167+
<MoreMenu>
168+
<MoreMenuTrigger>
169+
<ThreeDotsButton />
170+
</MoreMenuTrigger>
171+
<MoreMenuContent>
172+
<MoreMenuItem
173+
danger
174+
onClick={() => removeMember(member)}
175+
>
176+
Remove
177+
</MoreMenuItem>
178+
</MoreMenuContent>
179+
</MoreMenu>
180+
)}
181+
</TableCell>
182+
</TableRow>
183+
))
184+
) : (
185+
<TableRow>
186+
<TableCell colSpan={999}>
187+
<Loader />
177188
</TableCell>
178189
</TableRow>
179-
))}
190+
)}
180191
</TableBody>
181192
</Table>
182193
</PaginationContainer>

site/src/pages/UsersPage/UsersTable/UsersTableBody.tsx

+1-3
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,7 @@ export const UsersTableBody: FC<UsersTableBodyProps> = ({
8787
<TableLoaderSkeleton>
8888
<TableRowSkeleton>
8989
<TableCell>
90-
<div css={{ display: "flex", alignItems: "center", gap: 8 }}>
91-
<AvatarDataSkeleton />
92-
</div>
90+
<AvatarDataSkeleton />
9391
</TableCell>
9492

9593
<TableCell>

0 commit comments

Comments
 (0)