import React from "react"; import { Button } from "@/components/button.tsx"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "@/components/dialog.tsx"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/table.tsx"; import { Input } from "@/components/input.tsx"; import { Label } from "@/components/label.tsx"; import { Textarea } from "@/components/textarea.tsx"; import { Badge } from "@/components/badge.tsx"; import { Shield, Plus, Edit, Trash2 } from "lucide-react"; import { toast } from "sonner"; import { useTranslation } from "react-i18next"; import { useConfirmation } from "@/hooks/use-confirmation.ts"; import { getRoles, createRole, updateRole, deleteRole, type Role, } from "@/main-axios.ts"; export function RolesTab(): React.ReactElement { const { t } = useTranslation(); const { confirmWithToast } = useConfirmation(); const [roles, setRoles] = React.useState([]); const [loading, setLoading] = React.useState(false); const [roleDialogOpen, setRoleDialogOpen] = React.useState(false); const [editingRole, setEditingRole] = React.useState(null); const [roleName, setRoleName] = React.useState(""); const [roleDisplayName, setRoleDisplayName] = React.useState(""); const [roleDescription, setRoleDescription] = React.useState(""); const loadRoles = React.useCallback(async () => { setLoading(true); try { const response = await getRoles(); setRoles(response.roles || []); } catch (error) { toast.error(t("rbac.failedToLoadRoles")); console.error("Failed to load roles:", error); setRoles([]); } finally { setLoading(false); } }, [t]); React.useEffect(() => { loadRoles(); }, [loadRoles]); const handleCreateRole = () => { setEditingRole(null); setRoleName(""); setRoleDisplayName(""); setRoleDescription(""); setRoleDialogOpen(true); }; const handleEditRole = (role: Role) => { setEditingRole(role); setRoleName(role.name); setRoleDisplayName(role.displayName); setRoleDescription(role.description || ""); setRoleDialogOpen(true); }; const handleSaveRole = async () => { if (!roleDisplayName.trim()) { toast.error(t("rbac.roleDisplayNameRequired")); return; } if (!editingRole && !roleName.trim()) { toast.error(t("rbac.roleNameRequired")); return; } try { if (editingRole) { await updateRole(editingRole.id, { displayName: roleDisplayName, description: roleDescription || null, }); toast.success(t("rbac.roleUpdatedSuccessfully")); } else { await createRole({ name: roleName, displayName: roleDisplayName, description: roleDescription || null, }); toast.success(t("rbac.roleCreatedSuccessfully")); } setRoleDialogOpen(false); loadRoles(); } catch { toast.error(t("rbac.failedToSaveRole")); } }; const handleDeleteRole = async (role: Role) => { const confirmed = await confirmWithToast({ title: t("rbac.confirmDeleteRole"), description: t("rbac.confirmDeleteRoleDescription", { name: role.displayName, }), confirmText: t("common.delete"), cancelText: t("common.cancel"), }); if (!confirmed) return; try { await deleteRole(role.id); toast.success(t("rbac.roleDeletedSuccessfully")); loadRoles(); } catch { toast.error(t("rbac.failedToDeleteRole")); } }; return (

{t("rbac.roleManagement")}

{t("rbac.roleName")} {t("rbac.displayName")} {t("rbac.description")} {t("rbac.type")} {t("common.actions")} {loading ? ( {t("common.loading")} ) : roles.length === 0 ? ( {t("rbac.noRoles")} ) : ( roles.map((role) => ( {role.name} {t(role.displayName)} {role.description || "-"} {role.isSystem ? ( {t("rbac.systemRole")} ) : ( {t("rbac.customRole")} )}
{!role.isSystem && ( <> )}
)) )}
{editingRole ? t("rbac.editRole") : t("rbac.createRole")} {editingRole ? t("rbac.editRoleDescription") : t("rbac.createRoleDescription")}
{!editingRole && (
setRoleName(e.target.value.toLowerCase())} placeholder="developer" disabled={!!editingRole} />

{t("rbac.roleNameHint")}

)}
setRoleDisplayName(e.target.value)} placeholder={t("rbac.displayNamePlaceholder")} />