feat(rbac): add roles and permissions
This commit is contained in:
parent
86a32a942c
commit
694b7bd09a
37 changed files with 2682 additions and 218 deletions
|
|
@ -20,6 +20,8 @@ import { Input } from "@/components/ui/input";
|
|||
import { Label } from "@/components/ui/label";
|
||||
import UserFormDialog from "@/components/users/UserFormDialog";
|
||||
import { api } from "@/lib/api";
|
||||
import { hasPermission } from "@/lib/permissions";
|
||||
import type { CurrentUser, Role } from "@/types/rbac";
|
||||
import type { User, UserPayload } from "@/types/user";
|
||||
|
||||
function getErrorMessage(error: unknown) {
|
||||
|
|
@ -41,6 +43,8 @@ function formatDateTime(value: string) {
|
|||
export default function UserDetailPage() {
|
||||
const params = useParams<{ id: string }>();
|
||||
const [user, setUser] = useState<User | null>(null);
|
||||
const [roles, setRoles] = useState<Role[]>([]);
|
||||
const [currentUser, setCurrentUser] = useState<CurrentUser | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState("");
|
||||
const [pending, setPending] = useState(false);
|
||||
|
|
@ -52,8 +56,19 @@ export default function UserDetailPage() {
|
|||
|
||||
const loadUser = useCallback(async () => {
|
||||
try {
|
||||
const response = await api.get<User>(`/users/${params.id}`);
|
||||
setUser(response.data);
|
||||
const [userResponse, meResponse] = await Promise.all([
|
||||
api.get<User>(`/users/${params.id}`),
|
||||
api.get<CurrentUser>("/me"),
|
||||
]);
|
||||
setUser(userResponse.data);
|
||||
setCurrentUser(meResponse.data);
|
||||
|
||||
if (hasPermission(meResponse.data, "roles.read")) {
|
||||
const rolesResponse = await api.get<Role[]>("/roles");
|
||||
setRoles(rolesResponse.data);
|
||||
} else {
|
||||
setRoles([userResponse.data.primary_role]);
|
||||
}
|
||||
} catch (err) {
|
||||
setError(getErrorMessage(err));
|
||||
} finally {
|
||||
|
|
@ -147,14 +162,18 @@ export default function UserDetailPage() {
|
|||
</div>
|
||||
|
||||
<div className="flex gap-2">
|
||||
<Button type="button" variant="outline" onClick={() => setPasswordOpen(true)}>
|
||||
<KeyRound size={16} />
|
||||
Passwort ändern
|
||||
</Button>
|
||||
<Button type="button" onClick={() => setFormOpen(true)}>
|
||||
<Pencil size={16} />
|
||||
Bearbeiten
|
||||
</Button>
|
||||
{hasPermission(currentUser, "users.password.update") && (
|
||||
<Button type="button" variant="outline" onClick={() => setPasswordOpen(true)}>
|
||||
<KeyRound size={16} />
|
||||
Passwort ändern
|
||||
</Button>
|
||||
)}
|
||||
{hasPermission(currentUser, "users.update") && (
|
||||
<Button type="button" onClick={() => setFormOpen(true)}>
|
||||
<Pencil size={16} />
|
||||
Bearbeiten
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -165,7 +184,7 @@ export default function UserDetailPage() {
|
|||
<Detail label="Nachname" value={user.last_name || "-"} />
|
||||
<Detail label="Benutzername" value={user.username} />
|
||||
<Detail label="E-Mail" value={user.email} />
|
||||
<Detail label="Rolle" value={user.role} />
|
||||
<Detail label="Rolle" value={user.primary_role.display_name} />
|
||||
<div>
|
||||
<dt className="text-sm text-slate-500">Status</dt>
|
||||
<dd className="mt-1"><StatusBadge active={user.is_active} /></dd>
|
||||
|
|
@ -180,6 +199,7 @@ export default function UserDetailPage() {
|
|||
user={user}
|
||||
pending={pending}
|
||||
serverError={formError}
|
||||
roles={roles}
|
||||
onOpenChange={setFormOpen}
|
||||
onSubmit={saveUser}
|
||||
/>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue