mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-04-27 01:36:30 +02:00
refactor: complete RBAC migration cleanup - remove unused hooks and fix type imports
This commit is contained in:
parent
1c00e6f12e
commit
9c378550ba
3 changed files with 14 additions and 193 deletions
|
|
@ -49,12 +49,11 @@ import { toast } from "sonner";
|
||||||
import { updateMemberMutationAtom, deleteMemberMutationAtom } from "@/atoms/members/members-mutation.atoms";
|
import { updateMemberMutationAtom, deleteMemberMutationAtom } from "@/atoms/members/members-mutation.atoms";
|
||||||
import { myAccessAtom } from "@/atoms/members/members-query.atoms";
|
import { myAccessAtom } from "@/atoms/members/members-query.atoms";
|
||||||
import { createInviteMutationAtom, deleteInviteMutationAtom } from '@/atoms/invites/invites-mutation.atoms';
|
import { createInviteMutationAtom, deleteInviteMutationAtom } from '@/atoms/invites/invites-mutation.atoms';
|
||||||
import type { CreateInviteRequest, DeleteInviteRequest } from '@/contracts/types/invites.types';
|
import type { DeleteInviteRequest } from '@/contracts/types/invites.types';
|
||||||
import type { UpdateMembershipRequest, DeleteMembershipRequest, Membership } from "@/contracts/types/members.types";
|
import type { UpdateMembershipRequest, DeleteMembershipRequest} from "@/contracts/types/members.types";
|
||||||
import { permissionsAtom } from "@/atoms/permissions/permissions-query.atoms";
|
import { permissionsAtom } from "@/atoms/permissions/permissions-query.atoms";
|
||||||
import { membersAtom } from "@/atoms/members/members-query.atoms";
|
import { membersAtom } from "@/atoms/members/members-query.atoms";
|
||||||
import { invitesApiService } from '@/lib/apis/invites-api.service';
|
import { invitesApiService } from '@/lib/apis/invites-api.service';
|
||||||
import type { Invite } from '@/contracts/types/invites.types';
|
|
||||||
import {
|
import {
|
||||||
AlertDialog,
|
AlertDialog,
|
||||||
AlertDialogAction,
|
AlertDialogAction,
|
||||||
|
|
@ -117,9 +116,10 @@ import type {
|
||||||
UpdateRoleRequest,
|
UpdateRoleRequest,
|
||||||
} from "@/contracts/types/roles.types";
|
} from "@/contracts/types/roles.types";
|
||||||
import {
|
import {
|
||||||
type InviteCreate,
|
type Invite,
|
||||||
type Member,
|
type CreateInviteRequest,
|
||||||
} from "@/hooks/use-rbac";
|
} from "@/contracts/types/invites.types";
|
||||||
|
import type { Membership } from "@/contracts/types/members.types";
|
||||||
import { rolesApiService } from "@/lib/apis/roles-api.service";
|
import { rolesApiService } from "@/lib/apis/roles-api.service";
|
||||||
import { cacheKeys } from "@/lib/query-client/cache-keys";
|
import { cacheKeys } from "@/lib/query-client/cache-keys";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
|
@ -165,8 +165,7 @@ export default function TeamManagementPage() {
|
||||||
[access]
|
[access]
|
||||||
);
|
);
|
||||||
|
|
||||||
const { data: membersData = [], isLoading: membersLoading, refetch: fetchMembers } = useAtomValue(membersAtom);
|
const { data: members = [], isLoading: membersLoading, refetch: fetchMembers } = useAtomValue(membersAtom);
|
||||||
const members = membersData as Member[];
|
|
||||||
|
|
||||||
const { mutateAsync: createRole } = useAtomValue(createRoleMutationAtom);
|
const { mutateAsync: createRole } = useAtomValue(createRoleMutationAtom);
|
||||||
const { mutateAsync: updateRole } = useAtomValue(updateRoleMutationAtom);
|
const { mutateAsync: updateRole } = useAtomValue(updateRoleMutationAtom);
|
||||||
|
|
@ -190,7 +189,7 @@ export default function TeamManagementPage() {
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleCreateInvite = useCallback(
|
const handleCreateInvite = useCallback(
|
||||||
async (inviteData: InviteCreate) => {
|
async (inviteData: CreateInviteRequest['data']) => {
|
||||||
const request: CreateInviteRequest = {
|
const request: CreateInviteRequest = {
|
||||||
search_space_id: searchSpaceId,
|
search_space_id: searchSpaceId,
|
||||||
data: inviteData,
|
data: inviteData,
|
||||||
|
|
@ -236,7 +235,7 @@ export default function TeamManagementPage() {
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleUpdateMember = useCallback(
|
const handleUpdateMember = useCallback(
|
||||||
async (membershipId: number, roleId: number | null): Promise<Member> => {
|
async (membershipId: number, roleId: number | null): Promise<Membership> => {
|
||||||
const request: UpdateMembershipRequest = {
|
const request: UpdateMembershipRequest = {
|
||||||
search_space_id: searchSpaceId,
|
search_space_id: searchSpaceId,
|
||||||
membership_id: membershipId,
|
membership_id: membershipId,
|
||||||
|
|
@ -244,7 +243,7 @@ export default function TeamManagementPage() {
|
||||||
role_id: roleId,
|
role_id: roleId,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
return await updateMember(request) as Member;
|
return await updateMember(request) as Membership;
|
||||||
},
|
},
|
||||||
[updateMember, searchSpaceId]
|
[updateMember, searchSpaceId]
|
||||||
);
|
);
|
||||||
|
|
@ -511,10 +510,10 @@ function MembersTab({
|
||||||
canManageRoles,
|
canManageRoles,
|
||||||
canRemove,
|
canRemove,
|
||||||
}: {
|
}: {
|
||||||
members: Member[];
|
members: Membership[];
|
||||||
roles: Role[];
|
roles: Role[];
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
onUpdateRole: (membershipId: number, roleId: number | null) => Promise<Member>;
|
onUpdateRole: (membershipId: number, roleId: number | null) => Promise<Membership>;
|
||||||
onRemoveMember: (membershipId: number) => Promise<boolean>;
|
onRemoveMember: (membershipId: number) => Promise<boolean>;
|
||||||
canManageRoles: boolean;
|
canManageRoles: boolean;
|
||||||
canRemove: boolean;
|
canRemove: boolean;
|
||||||
|
|
@ -1078,7 +1077,7 @@ function CreateInviteDialog({
|
||||||
searchSpaceId,
|
searchSpaceId,
|
||||||
}: {
|
}: {
|
||||||
roles: Role[];
|
roles: Role[];
|
||||||
onCreateInvite: (data: InviteCreate) => Promise<Invite>;
|
onCreateInvite: (data: CreateInviteRequest['data']) => Promise<Invite>;
|
||||||
searchSpaceId: number;
|
searchSpaceId: number;
|
||||||
}) {
|
}) {
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
|
|
@ -1093,7 +1092,7 @@ function CreateInviteDialog({
|
||||||
const handleCreate = async () => {
|
const handleCreate = async () => {
|
||||||
setCreating(true);
|
setCreating(true);
|
||||||
try {
|
try {
|
||||||
const data: InviteCreate = {};
|
const data: CreateInviteRequest['data'] = {};
|
||||||
if (name) data.name = name;
|
if (name) data.name = name;
|
||||||
if (roleId && roleId !== "default") data.role_id = Number(roleId);
|
if (roleId && roleId !== "default") data.role_id = Number(roleId);
|
||||||
if (maxUses) data.max_uses = Number(maxUses);
|
if (maxUses) data.max_uses = Number(maxUses);
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
export * from "./use-debounced-value";
|
export * from "./use-debounced-value";
|
||||||
export * from "./use-logs";
|
export * from "./use-logs";
|
||||||
export * from "./use-rbac";
|
|
||||||
export * from "./use-search-source-connectors";
|
export * from "./use-search-source-connectors";
|
||||||
|
|
|
||||||
|
|
@ -1,177 +0,0 @@
|
||||||
"use client";
|
|
||||||
|
|
||||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
||||||
import { toast } from "sonner";
|
|
||||||
import { authenticatedFetch, getBearerToken, handleUnauthorized } from "@/lib/auth-utils";
|
|
||||||
|
|
||||||
// ============ Types ============
|
|
||||||
|
|
||||||
export interface Role {
|
|
||||||
id: number;
|
|
||||||
name: string;
|
|
||||||
description: string | null;
|
|
||||||
permissions: string[];
|
|
||||||
is_default: boolean;
|
|
||||||
is_system_role: boolean;
|
|
||||||
search_space_id: number;
|
|
||||||
created_at: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Member {
|
|
||||||
id: number;
|
|
||||||
user_id: string;
|
|
||||||
search_space_id: number;
|
|
||||||
role_id: number | null;
|
|
||||||
is_owner: boolean;
|
|
||||||
joined_at: string;
|
|
||||||
created_at: string;
|
|
||||||
role: Role | null;
|
|
||||||
user_email: string | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Invite {
|
|
||||||
id: number;
|
|
||||||
invite_code: string;
|
|
||||||
search_space_id: number;
|
|
||||||
role_id: number | null;
|
|
||||||
created_by_id: string | null;
|
|
||||||
expires_at: string | null;
|
|
||||||
max_uses: number | null;
|
|
||||||
uses_count: number;
|
|
||||||
is_active: boolean;
|
|
||||||
name: string | null;
|
|
||||||
created_at: string;
|
|
||||||
role: Role | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface InviteCreate {
|
|
||||||
name?: string;
|
|
||||||
role_id?: number;
|
|
||||||
expires_at?: string;
|
|
||||||
max_uses?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface InviteUpdate {
|
|
||||||
name?: string;
|
|
||||||
role_id?: number;
|
|
||||||
expires_at?: string;
|
|
||||||
max_uses?: number;
|
|
||||||
is_active?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface RoleCreate {
|
|
||||||
name: string;
|
|
||||||
description?: string;
|
|
||||||
permissions: string[];
|
|
||||||
is_default?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface RoleUpdate {
|
|
||||||
name?: string;
|
|
||||||
description?: string;
|
|
||||||
permissions?: string[];
|
|
||||||
is_default?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface PermissionInfo {
|
|
||||||
value: string;
|
|
||||||
name: string;
|
|
||||||
category: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface UserAccess {
|
|
||||||
search_space_id: number;
|
|
||||||
search_space_name: string;
|
|
||||||
is_owner: boolean;
|
|
||||||
role_name: string | null;
|
|
||||||
permissions: string[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface InviteInfo {
|
|
||||||
search_space_name: string;
|
|
||||||
role_name: string | null;
|
|
||||||
is_valid: boolean;
|
|
||||||
message: string | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============ Members Hook ============
|
|
||||||
|
|
||||||
export function useInviteInfo(inviteCode: string | null) {
|
|
||||||
const [inviteInfo, setInviteInfo] = useState<InviteInfo | null>(null);
|
|
||||||
const [loading, setLoading] = useState(true);
|
|
||||||
const [error, setError] = useState<string | null>(null);
|
|
||||||
|
|
||||||
const fetchInviteInfo = useCallback(async () => {
|
|
||||||
if (!inviteCode) {
|
|
||||||
setLoading(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
setLoading(true);
|
|
||||||
const response = await fetch(
|
|
||||||
`${process.env.NEXT_PUBLIC_FASTAPI_BACKEND_URL}/api/v1/invites/${inviteCode}/info`,
|
|
||||||
{
|
|
||||||
method: "GET",
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
const errorData = await response.json().catch(() => ({}));
|
|
||||||
throw new Error(errorData.detail || "Failed to fetch invite info");
|
|
||||||
}
|
|
||||||
|
|
||||||
const data = await response.json();
|
|
||||||
setInviteInfo(data);
|
|
||||||
setError(null);
|
|
||||||
return data;
|
|
||||||
} catch (err: any) {
|
|
||||||
setError(err.message || "Failed to fetch invite info");
|
|
||||||
console.error("Error fetching invite info:", err);
|
|
||||||
} finally {
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
}, [inviteCode]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
fetchInviteInfo();
|
|
||||||
}, [fetchInviteInfo]);
|
|
||||||
|
|
||||||
const acceptInvite = useCallback(async () => {
|
|
||||||
if (!inviteCode) {
|
|
||||||
toast.error("No invite code provided");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await authenticatedFetch(
|
|
||||||
`${process.env.NEXT_PUBLIC_FASTAPI_BACKEND_URL}/api/v1/invites/accept`,
|
|
||||||
{
|
|
||||||
headers: { "Content-Type": "application/json" },
|
|
||||||
method: "POST",
|
|
||||||
body: JSON.stringify({ invite_code: inviteCode }),
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
const errorData = await response.json().catch(() => ({}));
|
|
||||||
throw new Error(errorData.detail || "Failed to accept invite");
|
|
||||||
}
|
|
||||||
|
|
||||||
const data = await response.json();
|
|
||||||
toast.success(data.message || "Successfully joined the search space");
|
|
||||||
return data;
|
|
||||||
} catch (err: any) {
|
|
||||||
toast.error(err.message || "Failed to accept invite");
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
}, [inviteCode]);
|
|
||||||
|
|
||||||
return {
|
|
||||||
inviteInfo,
|
|
||||||
loading,
|
|
||||||
error,
|
|
||||||
fetchInviteInfo,
|
|
||||||
acceptInvite,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue