import { useCallback, useEffect, useState } from "react"; import ActivityIndicator from "@/components/indicators/activity-indicator"; import { FrigateConfig } from "@/types/frigateConfig"; import { Toaster } from "@/components/ui/sonner"; import useSWR from "swr"; import Heading from "@/components/ui/heading"; import { User } from "@/types/user"; import { Button } from "@/components/ui/button"; import SetPasswordDialog from "@/components/overlay/SetPasswordDialog"; import axios from "axios"; import CreateUserDialog from "@/components/overlay/CreateUserDialog"; import { toast } from "sonner"; import DeleteUserDialog from "@/components/overlay/DeleteUserDialog"; import { HiTrash } from "react-icons/hi"; import { FaUserEdit } from "react-icons/fa"; import { LuPlus, LuShield, LuUserCog } from "react-icons/lu"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table"; import { Badge } from "@/components/ui/badge"; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from "@/components/ui/tooltip"; import RoleChangeDialog from "@/components/overlay/RoleChangeDialog"; import { useTranslation } from "react-i18next"; export default function AuthenticationView() { const { t } = useTranslation("views/settings"); const { data: config } = useSWR("config"); const { data: users, mutate: mutateUsers } = useSWR("users"); const [showSetPassword, setShowSetPassword] = useState(false); const [showCreate, setShowCreate] = useState(false); const [showDelete, setShowDelete] = useState(false); const [showRoleChange, setShowRoleChange] = useState(false); const [selectedUser, setSelectedUser] = useState(); const [selectedUserRole, setSelectedUserRole] = useState< "admin" | "viewer" >(); useEffect(() => { document.title = t("documentTitle.authentication"); }, [t]); const onSavePassword = useCallback( (user: string, password: string) => { axios .put(`users/${user}/password`, { password }) .then((response) => { if (response.status === 200) { setShowSetPassword(false); toast.success(t("users.toast.success.updatePassword"), { position: "top-center", }); } }) .catch((error) => { const errorMessage = error.response?.data?.message || error.response?.data?.detail || "Unknown error"; toast.error( t("users.toast.error.setPasswordFailed", { errorMessage, }), { position: "top-center", }, ); }); }, [t], ); const onCreate = ( user: string, password: string, role: "admin" | "viewer", ) => { axios .post("users", { username: user, password, role }) .then((response) => { if (response.status === 200 || response.status === 201) { setShowCreate(false); mutateUsers((users) => { users?.push({ username: user, role: role }); return users; }, false); toast.success(t("users.toast.success.createUser", { user }), { position: "top-center", }); } }) .catch((error) => { const errorMessage = error.response?.data?.message || error.response?.data?.detail || "Unknown error"; toast.error( t("users.toast.error.createUserFailed", { errorMessage, }), { position: "top-center", }, ); }); }; const onDelete = (user: string) => { axios .delete(`users/${user}`) .then((response) => { if (response.status === 200) { setShowDelete(false); mutateUsers( (users) => users?.filter((u) => u.username !== user), false, ); toast.success(t("users.toast.success.deleteUser", { user }), { position: "top-center", }); } }) .catch((error) => { const errorMessage = error.response?.data?.message || error.response?.data?.detail || "Unknown error"; toast.error( t("users.toast.error.deleteUserFailed", { errorMessage, }), { position: "top-center", }, ); }); }; const onChangeRole = (user: string, newRole: "admin" | "viewer") => { if (user === "admin") return; // Prevent role change for 'admin' axios .put(`users/${user}/role`, { role: newRole }) .then((response) => { if (response.status === 200) { setShowRoleChange(false); mutateUsers( (users) => users?.map((u) => u.username === user ? { ...u, role: newRole } : u, ), false, ); toast.success(t("users.toast.success.roleUpdated", { user }), { position: "top-center", }); } }) .catch((error) => { const errorMessage = error.response?.data?.message || error.response?.data?.detail || "Unknown error"; toast.error( t("users.toast.error.roleUpdateFailed", { errorMessage, }), { position: "top-center", }, ); }); }; if (!config || !users) { return (
); } return (
{t("users.management")}

{t("users.management.desc")}

{t("users.table.username")} {t("users.table.role")} {t("users.table.actions")} {users.length === 0 ? ( {t("users.table.noUsers")} ) : ( users.map((user) => (
{user.username === "admin" ? ( ) : ( )} {user.username}
{t("role." + (user.role || "viewer"), { ns: "common", })}
{user.username !== "admin" && (

{t("users.table.changeRole")}

)}

{t("users.updatePassword")}

{user.username !== "admin" && (

{t("users.table.deleteUser")}

)}
)) )}
setShowSetPassword(false)} onSave={(password) => onSavePassword(selectedUser!, password)} /> setShowDelete(false)} onDelete={() => onDelete(selectedUser!)} /> setShowCreate(false)} /> {selectedUser && selectedUserRole && ( onChangeRole(selectedUser, role)} onCancel={() => setShowRoleChange(false)} /> )}
); }