mirror of
https://github.com/fosrl/pangolin.git
synced 2026-03-30 14:36:46 +00:00
ui improvements
This commit is contained in:
@@ -95,7 +95,8 @@ function getActionsCategories(root: boolean) {
|
||||
[t("actionListRole")]: "listRoles",
|
||||
[t("actionUpdateRole")]: "updateRole",
|
||||
[t("actionListAllowedRoleResources")]: "listRoleResources",
|
||||
[t("actionAddUserRole")]: "addUserRole"
|
||||
[t("actionAddUserRole")]: "addUserRole",
|
||||
[t("actionSetUserOrgRoles")]: "setUserOrgRoles"
|
||||
},
|
||||
"Access Token": {
|
||||
[t("actionGenerateAccessToken")]: "generateAccessToken",
|
||||
|
||||
@@ -12,6 +12,13 @@ import { Button } from "@app/components/ui/button";
|
||||
import { ArrowRight, ArrowUpDown, Crown, MoreHorizontal } from "lucide-react";
|
||||
import { UsersDataTable } from "@app/components/UsersDataTable";
|
||||
import { useState, useEffect } from "react";
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger
|
||||
} from "@app/components/ui/popover";
|
||||
import { Badge, badgeVariants } from "@app/components/ui/badge";
|
||||
import { cn } from "@app/lib/cn";
|
||||
import ConfirmDeleteDialog from "@app/components/ConfirmDeleteDialog";
|
||||
import { useOrgContext } from "@app/hooks/useOrgContext";
|
||||
import { toast } from "@app/hooks/useToast";
|
||||
@@ -36,10 +43,65 @@ export type UserRow = {
|
||||
type: string;
|
||||
idpVariant: string | null;
|
||||
status: string;
|
||||
role: string;
|
||||
roleLabels: string[];
|
||||
isOwner: boolean;
|
||||
};
|
||||
|
||||
const MAX_ROLE_BADGES = 3;
|
||||
|
||||
function UserRoleBadges({ roleLabels }: { roleLabels: string[] }) {
|
||||
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">
|
||||
{visible.map((label, i) => (
|
||||
<Badge key={`${label}-${i}`} variant="secondary">
|
||||
{label}
|
||||
</Badge>
|
||||
))}
|
||||
{overflow.length > 0 && (
|
||||
<OverflowRolesPopover labels={overflow} />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function OverflowRolesPopover({ labels }: { labels: string[] }) {
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<Popover open={open} onOpenChange={setOpen}>
|
||||
<PopoverTrigger asChild>
|
||||
<button
|
||||
type="button"
|
||||
className={cn(
|
||||
badgeVariants({ variant: "secondary" }),
|
||||
"border-dashed"
|
||||
)}
|
||||
onMouseEnter={() => setOpen(true)}
|
||||
onMouseLeave={() => setOpen(false)}
|
||||
>
|
||||
+{labels.length}
|
||||
</button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent
|
||||
align="start"
|
||||
side="top"
|
||||
className="w-auto max-w-xs p-2"
|
||||
onMouseEnter={() => setOpen(true)}
|
||||
onMouseLeave={() => setOpen(false)}
|
||||
>
|
||||
<ul className="space-y-1 text-sm">
|
||||
{labels.map((label, i) => (
|
||||
<li key={`${label}-${i}`}>{label}</li>
|
||||
))}
|
||||
</ul>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
);
|
||||
}
|
||||
|
||||
type UsersTableProps = {
|
||||
users: UserRow[];
|
||||
};
|
||||
@@ -124,7 +186,8 @@ export default function UsersTable({ users: u }: UsersTableProps) {
|
||||
}
|
||||
},
|
||||
{
|
||||
accessorKey: "role",
|
||||
id: "role",
|
||||
accessorFn: (row) => row.roleLabels.join(", "),
|
||||
friendlyName: t("role"),
|
||||
header: ({ column }) => {
|
||||
return (
|
||||
@@ -140,13 +203,7 @@ export default function UsersTable({ users: u }: UsersTableProps) {
|
||||
);
|
||||
},
|
||||
cell: ({ row }) => {
|
||||
const userRow = row.original;
|
||||
|
||||
return (
|
||||
<div className="flex flex-row items-center gap-2">
|
||||
<span>{userRow.role}</span>
|
||||
</div>
|
||||
);
|
||||
return <UserRoleBadges roleLabels={row.original.roleLabels} />;
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -4,7 +4,7 @@ import { cva, type VariantProps } from "class-variance-authority";
|
||||
import { cn } from "@app/lib/cn";
|
||||
|
||||
const badgeVariants = cva(
|
||||
"inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-0",
|
||||
"inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors outline-none focus:outline-none focus-visible:outline-none focus-visible:ring-0",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
|
||||
Reference in New Issue
Block a user