move improvements to user management ui

This commit is contained in:
miloschwartz
2026-09-11 11:58:51 -04:00
committed by Owen
parent 162dade852
commit dac8b5a132
13 changed files with 466 additions and 565 deletions
+1 -1
View File
@@ -227,7 +227,7 @@ function ApprovalRequest({ approval, orgId, onSuccess }: ApprovalRequestProps) {
<div className="inline-flex items-start md:items-center gap-2">
<span>
<Link
href={`/${orgId}/settings/access/users/${approval.user.userId}/access-controls`}
href={`/${orgId}/settings/access/users/${approval.user.userId}/general`}
className="text-primary hover:underline cursor-pointer"
>
{getUserDisplayName({
+9 -4
View File
@@ -8,27 +8,32 @@ import {
PopoverTrigger
} from "@app/components/ui/popover";
import { cn } from "@app/lib/cn";
import { useTranslations } from "next-intl";
const MAX_ROLE_BADGES = 3;
export default function UserRoleBadges({
roleLabels
roleLabels,
isOwner
}: {
roleLabels: string[];
isOwner?: boolean;
}) {
const t = useTranslations();
const visible = roleLabels.slice(0, MAX_ROLE_BADGES);
const overflow = roleLabels.slice(MAX_ROLE_BADGES);
return (
<div className="flex flex-wrap items-center gap-1">
{isOwner && (
<Badge variant="secondary">{t("accessRoleOwner")}</Badge>
)}
{visible.map((label, i) => (
<Badge key={`${label}-${i}`} variant="secondary">
{label}
</Badge>
))}
{overflow.length > 0 && (
<OverflowRolesPopover labels={overflow} />
)}
{overflow.length > 0 && <OverflowRolesPopover labels={overflow} />}
</div>
);
}
+35 -3
View File
@@ -22,6 +22,7 @@ import {
ArrowRight,
ArrowUp10Icon,
ChevronsUpDownIcon,
Crown,
MoreHorizontal
} from "lucide-react";
import { useTranslations } from "next-intl";
@@ -33,12 +34,20 @@ import z from "zod";
import { ColumnFilterButton } from "./ColumnFilterButton";
import { ColumnMultiFilterButton } from "./ColumnMultiFilterButton";
import IdpTypeBadge from "./IdpTypeBadge";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger
} from "./ui/tooltip";
import {
ControlledDataTable,
type ExtendedColumnDef
} from "./ui/controlled-data-table";
import UserRoleBadges from "./UserRoleBadges";
const OWNER_FILTER_VALUE = "owner";
export type UserRow = {
id: string;
email: string | null;
@@ -95,7 +104,13 @@ export default function UsersTable({
const roleIdsFromSearchParams = useMemo(() => {
const sp = new URLSearchParams(searchParams);
return [
...new Set(sp.getAll("role_id").filter((id) => /^\d+$/.test(id)))
...new Set(
sp
.getAll("role_id")
.filter(
(id) => /^\d+$/.test(id) || id === OWNER_FILTER_VALUE
)
)
];
}, [searchParams.toString()]);
@@ -126,7 +141,7 @@ export default function UsersTable({
sp.delete("role_id");
sp.delete("page");
for (const id of values) {
if (/^\d+$/.test(id)) {
if (/^\d+$/.test(id) || id === OWNER_FILTER_VALUE) {
sp.append("role_id", id);
}
}
@@ -183,6 +198,18 @@ export default function UsersTable({
<span className="text-primary">you</span>
</>
)}
{row.original.isOwner && (
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Crown className="text-primary size-4 flex-none" />
</TooltipTrigger>
<TooltipContent>
{t("accessRoleOwner")}
</TooltipContent>
</Tooltip>
</TooltipProvider>
)}
</span>
)
},
@@ -235,7 +262,12 @@ export default function UsersTable({
);
},
cell: ({ row }) => {
return <UserRoleBadges roleLabels={row.original.roleLabels} />;
return (
<UserRoleBadges
roleLabels={row.original.roleLabels}
isOwner={row.original.isOwner}
/>
);
}
},
{