diff --git a/.backend_env.example b/.backend_env.example index 03bbfcf73..cf6c2a1b3 100644 --- a/.backend_env.example +++ b/.backend_env.example @@ -6,8 +6,10 @@ JWT_SECRET_KEY= AUTHENTICATE=true GOOGLE_APPLICATION_CREDENTIALS= GOOGLE_CLOUD_PROJECT= + MAX_BRAIN_SIZE=52428800 MAX_REQUESTS_NUMBER=200 +MAX_BRAIN_PER_USER=5 #Private LLM Variables PRIVATE=False diff --git a/backend/core/models/brains.py b/backend/core/models/brains.py index 109ce0d77..56f22d75f 100644 --- a/backend/core/models/brains.py +++ b/backend/core/models/brains.py @@ -1,4 +1,3 @@ -import os from typing import Any, List, Optional from uuid import UUID @@ -6,7 +5,7 @@ from logger import get_logger from pydantic import BaseModel from utils.vectors import get_unique_files_from_vector_ids -from models.settings import CommonsDep, common_dependencies +from models.settings import BrainRateLimiting, CommonsDep, common_dependencies from models.users import User logger = get_logger(__name__) @@ -19,12 +18,16 @@ class Brain(BaseModel): model: Optional[str] = "gpt-3.5-turbo-0613" temperature: Optional[float] = 0.0 max_tokens: Optional[int] = 256 - max_brain_size: Optional[int] = int(os.getenv("MAX_BRAIN_SIZE", 52428800)) files: List[Any] = [] class Config: arbitrary_types_allowed = True + @property + def max_brain_size(self) -> int: + brain_rate_limiting = BrainRateLimiting() + return brain_rate_limiting.max_brain_size + @property def commons(self) -> CommonsDep: return common_dependencies() diff --git a/backend/core/models/settings.py b/backend/core/models/settings.py index aaaadb9a7..448b2c996 100644 --- a/backend/core/models/settings.py +++ b/backend/core/models/settings.py @@ -7,6 +7,11 @@ from supabase.client import Client, create_client from vectorstore.supabase import SupabaseVectorStore +class BrainRateLimiting(BaseSettings): + max_brain_size = 52428800 + max_brain_per_user = 5 + + class BrainSettings(BaseSettings): openai_api_key: str anthropic_api_key: str diff --git a/backend/core/routes/brain_routes.py b/backend/core/routes/brain_routes.py index f88c337dc..efe0062e7 100644 --- a/backend/core/routes/brain_routes.py +++ b/backend/core/routes/brain_routes.py @@ -8,7 +8,7 @@ from models.brains import ( get_default_user_brain, get_default_user_brain_or_create_new, ) -from models.settings import common_dependencies +from models.settings import BrainRateLimiting, common_dependencies from models.users import User from routes.authorizations.brain_authorization import has_brain_authorization @@ -104,6 +104,15 @@ async def create_brain_endpoint( brain = Brain(name=brain.name) # pyright: ignore reportPrivateUsage=none + user_brains = brain.get_user_brains(current_user.id) + max_brain_per_user = BrainRateLimiting().max_brain_per_user + + if len(user_brains) >= max_brain_per_user: + raise HTTPException( + status_code=429, + detail=f"Maximum number of brains reached ({max_brain_per_user}).", + ) + brain.create_brain() # pyright: ignore reportPrivateUsage=none default_brain = get_default_user_brain(current_user) if default_brain: diff --git a/backend/core/routes/user_routes.py b/backend/core/routes/user_routes.py index 907262a26..ae0b68c8f 100644 --- a/backend/core/routes/user_routes.py +++ b/backend/core/routes/user_routes.py @@ -4,6 +4,7 @@ import time from auth import AuthBearer, get_current_user from fastapi import APIRouter, Depends, Request from models.brains import Brain, get_default_user_brain +from models.settings import BrainRateLimiting from models.users import User user_router = APIRouter() @@ -32,7 +33,8 @@ async def get_user_endpoint( information about the user's API usage. """ - max_brain_size = int(os.getenv("MAX_BRAIN_SIZE", 52428800)) + max_brain_size = BrainRateLimiting().max_brain_size + if request.headers.get("Openai-Api-Key"): max_brain_size = MAX_BRAIN_SIZE_WITH_OWN_KEY diff --git a/frontend/app/explore/DocumentItem/index.tsx b/frontend/app/explore/DocumentItem/index.tsx index b2a248743..14750f6ae 100644 --- a/frontend/app/explore/DocumentItem/index.tsx +++ b/frontend/app/explore/DocumentItem/index.tsx @@ -34,7 +34,7 @@ const DocumentItem = forwardRef( const { track } = useEventTracking(); const { currentBrain } = useBrainContext(); - const canDeleteFile = currentBrain?.rights === "Owner"; + const canDeleteFile = currentBrain?.role === "Owner"; if (!session) { throw new Error("User session not found"); diff --git a/frontend/app/invitation/[brainId]/hooks/useInvitation.ts b/frontend/app/invitation/[brainId]/hooks/useInvitation.ts index d7ce7ed6d..7aa32d448 100644 --- a/frontend/app/invitation/[brainId]/hooks/useInvitation.ts +++ b/frontend/app/invitation/[brainId]/hooks/useInvitation.ts @@ -17,7 +17,7 @@ export const useInvitation = () => { const brainId = params?.brainId as UUID | undefined; const [isLoading, setIsLoading] = useState(false); const [brainName, setBrainName] = useState(""); - const [rights, setRights] = useState(); + const [role, setRole] = useState(); const [isProcessingRequest, setIsProcessingRequest] = useState(false); const { publish } = useToast(); @@ -37,9 +37,9 @@ export const useInvitation = () => { const checkInvitationValidity = async () => { try { - const { name, rights: assignedRights } = await getInvitation(brainId); + const { name, role: assignedRole } = await getInvitation(brainId); setBrainName(name); - setRights(assignedRights); + setRole(assignedRole); } catch (error) { if (axios.isAxiosError(error) && error.response?.status === 404) { publish({ @@ -130,7 +130,7 @@ export const useInvitation = () => { handleAccept, handleDecline, brainName, - rights, + role, isLoading, isProcessingRequest, }; diff --git a/frontend/app/invitation/[brainId]/page.tsx b/frontend/app/invitation/[brainId]/page.tsx index 10f8e316c..f0c77c6f0 100644 --- a/frontend/app/invitation/[brainId]/page.tsx +++ b/frontend/app/invitation/[brainId]/page.tsx @@ -15,7 +15,7 @@ const InvitationPage = (): JSX.Element => { handleDecline, isLoading, brainName, - rights, + role, } = useInvitation(); const { session } = useSupabase(); @@ -27,15 +27,18 @@ const InvitationPage = (): JSX.Element => { redirectToLogin(); } - if (rights === undefined) { - throw new Error("Rights are undefined"); + if (role === undefined) { + // This should never happen + // It is a way to prevent the page from crashing when invitation is invalid instead of throwing an error + // The user will be redirected to the home page (handled in the useInvitation hook) + return
; } return (
{isProcessingRequest ? (
diff --git a/frontend/app/upload/page.tsx b/frontend/app/upload/page.tsx index 6712ecdc8..0a6b2c72a 100644 --- a/frontend/app/upload/page.tsx +++ b/frontend/app/upload/page.tsx @@ -35,7 +35,7 @@ const UploadPage = (): JSX.Element => { ); } - const hasUploadRights = requiredRolesForUpload.includes(currentBrain.rights); + const hasUploadRights = requiredRolesForUpload.includes(currentBrain.role); if (!hasUploadRights) { return ( @@ -44,7 +44,7 @@ const UploadPage = (): JSX.Element => { Oh no! { - "You don't have the necessary rights to upload content to the selected brain. 🧠💡🥲" + "You don't have the necessary role to upload content to the selected brain. 🧠💡🥲" }
diff --git a/frontend/lib/api/brain/__tests__/useBrainApi.test.ts b/frontend/lib/api/brain/__tests__/useBrainApi.test.ts index e139c4527..31a1649e8 100644 --- a/frontend/lib/api/brain/__tests__/useBrainApi.test.ts +++ b/frontend/lib/api/brain/__tests__/useBrainApi.test.ts @@ -2,7 +2,8 @@ import { renderHook } from "@testing-library/react"; import { afterEach, describe, expect, it, vi } from "vitest"; -import { Subscription, SubscriptionUpdatableProperties } from "../brain"; +import { Subscription } from "../brain"; +import { SubscriptionUpdatableProperties } from "../types"; import { useBrainApi } from "../useBrainApi"; const axiosGetMock = vi.fn(() => ({ @@ -89,6 +90,12 @@ describe("useBrainApi", () => { }); it("should call getBrains with the correct parameters", async () => { + axiosGetMock.mockImplementationOnce(() => ({ + data: { + //@ts-ignore we don't really need returned value here + brains: [], + }, + })); const { result: { current: { getBrains }, @@ -123,19 +130,26 @@ describe("useBrainApi", () => { const subscriptions: Subscription[] = [ { email: "user@quivr.app", - rights: "Viewer", + role: "Viewer", }, ]; await addBrainSubscriptions(id, subscriptions); expect(axiosPostMock).toHaveBeenCalledTimes(1); - expect(axiosPostMock).toHaveBeenCalledWith( - `/brains/${id}/subscription`, - subscriptions - ); + expect(axiosPostMock).toHaveBeenCalledWith(`/brains/${id}/subscription`, [ + { + email: "user@quivr.app", + rights: "Viewer", + }, + ]); }); it("should call getBrainUsers with the correct parameters", async () => { + axiosGetMock.mockImplementationOnce(() => ({ + //@ts-ignore we don't really need returned value here + data: [], + })); + const { result: { current: { getBrainUsers }, @@ -156,13 +170,13 @@ describe("useBrainApi", () => { const brainId = "123"; const email = "456"; const subscription: SubscriptionUpdatableProperties = { - rights: "Viewer", + role: "Viewer", }; await updateBrainAccess(brainId, email, subscription); expect(axiosPutMock).toHaveBeenCalledTimes(1); expect(axiosPutMock).toHaveBeenCalledWith( `/brains/${brainId}/subscription`, - { ...subscription, email } + { rights: "Viewer", email } ); }); }); diff --git a/frontend/lib/api/brain/brain.ts b/frontend/lib/api/brain/brain.ts index 310eaafd8..7da9c64c6 100644 --- a/frontend/lib/api/brain/brain.ts +++ b/frontend/lib/api/brain/brain.ts @@ -1,9 +1,22 @@ +/* eslint-disable max-lines */ import { AxiosInstance } from "axios"; import { BrainRoleType } from "@/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/types"; -import { Brain, MinimalBrainForUser } from "@/lib/context/BrainProvider/types"; +import { + BackendMinimalBrainForUser, + Brain, + MinimalBrainForUser, +} from "@/lib/context/BrainProvider/types"; import { Document } from "@/lib/types/Document"; +import { SubscriptionUpdatableProperties } from "./types"; +import { mapBackendMinimalBrainToMinimalBrain } from "./utils/mapBackendMinimalBrainToMinimalBrain"; +import { + BackendSubscription, + mapSubscriptionToBackendSubscription, +} from "./utils/mapSubscriptionToBackendSubscription"; +import { mapSubscriptionUpdatablePropertiesToBackendSubscriptionUpdatableProperties } from "./utils/mapSubscriptionUpdatablePropertiesToBackendSubscriptionUpdatableProperties"; + export const getBrainDocuments = async ( brainId: string, axiosInstance: AxiosInstance @@ -19,11 +32,10 @@ export const createBrain = async ( name: string, axiosInstance: AxiosInstance ): Promise => { - const createdBrain = ( - await axiosInstance.post(`/brains/`, { name }) - ).data; - - return createdBrain; + return mapBackendMinimalBrainToMinimalBrain( + (await axiosInstance.post(`/brains/`, { name })) + .data + ); }; export const getBrain = async ( @@ -47,40 +59,49 @@ export const deleteBrain = async ( export const getDefaultBrain = async ( axiosInstance: AxiosInstance ): Promise => { - return (await axiosInstance.get(`/brains/default/`)) - .data; + return mapBackendMinimalBrainToMinimalBrain( + (await axiosInstance.get(`/brains/default/`)) + .data + ); }; export const getBrains = async ( axiosInstance: AxiosInstance ): Promise => { - const brains = ( - await axiosInstance.get<{ brains: MinimalBrainForUser[] }>(`/brains/`) + const { brains } = ( + await axiosInstance.get<{ brains: BackendMinimalBrainForUser[] }>( + `/brains/` + ) ).data; - return brains.brains; + return brains.map(mapBackendMinimalBrainToMinimalBrain); }; -export type Subscription = { email: string; rights: BrainRoleType }; +export type Subscription = { email: string; role: BrainRoleType }; export const addBrainSubscriptions = async ( brainId: string, subscriptions: Subscription[], axiosInstance: AxiosInstance ): Promise => { - await axiosInstance.post(`/brains/${brainId}/subscription`, subscriptions); + await axiosInstance.post( + `/brains/${brainId}/subscription`, + subscriptions.map(mapSubscriptionToBackendSubscription) + ); }; export const getBrainUsers = async ( brainId: string, axiosInstance: AxiosInstance ): Promise => { - return (await axiosInstance.get(`/brains/${brainId}/users`)) - .data; -}; + const brainsUsers = ( + await axiosInstance.get(`/brains/${brainId}/users`) + ).data; -export type SubscriptionUpdatableProperties = { - rights: BrainRoleType | null; + return brainsUsers.map((brainUser) => ({ + email: brainUser.email, + role: brainUser.rights, + })); }; export const updateBrainAccess = async ( @@ -90,7 +111,9 @@ export const updateBrainAccess = async ( axiosInstance: AxiosInstance ): Promise => { await axiosInstance.put(`/brains/${brainId}/subscription`, { - ...subscription, + ...mapSubscriptionUpdatablePropertiesToBackendSubscriptionUpdatableProperties( + subscription + ), email: userEmail, }); }; diff --git a/frontend/lib/api/brain/types.ts b/frontend/lib/api/brain/types.ts new file mode 100644 index 000000000..3a0546d3c --- /dev/null +++ b/frontend/lib/api/brain/types.ts @@ -0,0 +1,5 @@ +import { BrainRoleType } from "@/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/types"; + +export type SubscriptionUpdatableProperties = { + role: BrainRoleType | null; +}; diff --git a/frontend/lib/api/brain/useBrainApi.ts b/frontend/lib/api/brain/useBrainApi.ts index 84848f2f6..d9c915b32 100644 --- a/frontend/lib/api/brain/useBrainApi.ts +++ b/frontend/lib/api/brain/useBrainApi.ts @@ -10,9 +10,9 @@ import { getBrainUsers, getDefaultBrain, Subscription, - SubscriptionUpdatableProperties, updateBrainAccess, } from "./brain"; +import { SubscriptionUpdatableProperties } from "./types"; // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types export const useBrainApi = () => { diff --git a/frontend/lib/api/brain/utils/mapBackendMinimalBrainToMinimalBrain.ts b/frontend/lib/api/brain/utils/mapBackendMinimalBrainToMinimalBrain.ts new file mode 100644 index 000000000..d8e299f38 --- /dev/null +++ b/frontend/lib/api/brain/utils/mapBackendMinimalBrainToMinimalBrain.ts @@ -0,0 +1,12 @@ +import { + BackendMinimalBrainForUser, + MinimalBrainForUser, +} from "@/lib/context/BrainProvider/types"; + +export const mapBackendMinimalBrainToMinimalBrain = ( + backendMinimalBrain: BackendMinimalBrainForUser +): MinimalBrainForUser => ({ + id: backendMinimalBrain.id, + name: backendMinimalBrain.name, + role: backendMinimalBrain.rights, +}); diff --git a/frontend/lib/api/brain/utils/mapSubscriptionToBackendSubscription.ts b/frontend/lib/api/brain/utils/mapSubscriptionToBackendSubscription.ts new file mode 100644 index 000000000..ab65cdffa --- /dev/null +++ b/frontend/lib/api/brain/utils/mapSubscriptionToBackendSubscription.ts @@ -0,0 +1,12 @@ +import { BrainRoleType } from "@/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/types"; + +import { Subscription } from "../brain"; + +export type BackendSubscription = { email: string; rights: BrainRoleType }; + +export const mapSubscriptionToBackendSubscription = ( + subscription: Subscription +): BackendSubscription => ({ + email: subscription.email, + rights: subscription.role, +}); diff --git a/frontend/lib/api/brain/utils/mapSubscriptionUpdatablePropertiesToBackendSubscriptionUpdatableProperties.ts b/frontend/lib/api/brain/utils/mapSubscriptionUpdatablePropertiesToBackendSubscriptionUpdatableProperties.ts new file mode 100644 index 000000000..a9c7ff574 --- /dev/null +++ b/frontend/lib/api/brain/utils/mapSubscriptionUpdatablePropertiesToBackendSubscriptionUpdatableProperties.ts @@ -0,0 +1,13 @@ +import { BrainRoleType } from "@/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/types"; + +import { SubscriptionUpdatableProperties } from "../types"; + +type BackendSubscriptionUpdatableProperties = { + rights: BrainRoleType | null; +}; +export const mapSubscriptionUpdatablePropertiesToBackendSubscriptionUpdatableProperties = + ( + subscriptionUpdatableProperties: SubscriptionUpdatableProperties + ): BackendSubscriptionUpdatableProperties => ({ + rights: subscriptionUpdatableProperties.role, + }); diff --git a/frontend/lib/api/subscription/subscription.ts b/frontend/lib/api/subscription/subscription.ts index e5e8b0766..fca17e14f 100644 --- a/frontend/lib/api/subscription/subscription.ts +++ b/frontend/lib/api/subscription/subscription.ts @@ -13,8 +13,6 @@ export const acceptInvitation = async ( ) ).data; - console.log("acceptedInvitation", acceptedInvitation); - return acceptedInvitation; }; @@ -33,6 +31,11 @@ export const declineInvitation = async ( export type InvitationBrain = { name: string; + role: BrainRoleType; +}; + +//TODO: rename rights to role in Backend and use InvitationBrain instead of BackendInvitationBrain +type BackendInvitationBrain = Omit & { rights: BrainRoleType; }; @@ -40,7 +43,14 @@ export const getInvitation = async ( brainId: UUID, axiosInstance: AxiosInstance ): Promise => { - return ( - await axiosInstance.get(`/brains/${brainId}/subscription`) + const invitation = ( + await axiosInstance.get( + `/brains/${brainId}/subscription` + ) ).data; + + return { + name: invitation.name, + role: invitation.rights, + }; }; diff --git a/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/AddBrainModal.tsx b/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/AddBrainModal.tsx index 78eae2921..899a79cae 100644 --- a/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/AddBrainModal.tsx +++ b/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/AddBrainModal.tsx @@ -1,3 +1,4 @@ +import axios from "axios"; import { FormEvent, useState } from "react"; import { MdAdd } from "react-icons/md"; @@ -5,11 +6,12 @@ import Button from "@/lib/components/ui/Button"; import Field from "@/lib/components/ui/Field"; import { Modal } from "@/lib/components/ui/Modal"; import { useBrainContext } from "@/lib/context/BrainProvider/hooks/useBrainContext"; +import { useToast } from "@/lib/hooks"; export const AddBrainModal = (): JSX.Element => { const [newBrainName, setNewBrainName] = useState(""); const [isPending, setIsPending] = useState(false); - + const { publish } = useToast(); const { createBrain } = useBrainContext(); const handleSubmit = async (e: FormEvent) => { @@ -17,10 +19,31 @@ export const AddBrainModal = (): JSX.Element => { if (newBrainName.trim() === "" || isPending) { return; } - setIsPending(true); - await createBrain(newBrainName); - setNewBrainName(""); - setIsPending(false); + try { + setIsPending(true); + await createBrain(newBrainName); + setNewBrainName(""); + } catch (err) { + if (axios.isAxiosError(err) && err.response?.status === 429) { + publish({ + variant: "danger", + text: `${JSON.stringify( + ( + err.response as { + data: { detail: string }; + } + ).data.detail + )}`, + }); + } else { + publish({ + variant: "danger", + text: `${JSON.stringify(err)}`, + }); + } + } finally { + setIsPending(false); + } }; return ( diff --git a/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/BrainActions.tsx b/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/BrainActions.tsx index 3c055304d..8c89fb329 100644 --- a/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/BrainActions.tsx +++ b/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/BrainActions.tsx @@ -12,7 +12,7 @@ const requiredAccessToShareBrain: BrainRoleType[] = ["Owner", "Editor"]; export const BrainActions = ({ brain }: BrainActionsProps): JSX.Element => { return (
- {requiredAccessToShareBrain.includes(brain.rights) && ( + {requiredAccessToShareBrain.includes(brain.role) && ( )} diff --git a/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/components/ShareBrain/__tests__/ShareBrain.test.tsx b/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/components/ShareBrain/__tests__/ShareBrain.test.tsx index 29392dad3..b5c562d20 100644 --- a/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/components/ShareBrain/__tests__/ShareBrain.test.tsx +++ b/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/components/ShareBrain/__tests__/ShareBrain.test.tsx @@ -39,7 +39,7 @@ vi.mock("@/lib/context/BrainProvider/hooks/useBrainContext", async () => { useBrainContext: () => ({ ...actual.useBrainContext(), currentBrain: { - rights: "Editor", + role: "Editor", }, }), }; diff --git a/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/components/ShareBrain/components/BrainUsers/BrainUsers.tsx b/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/components/ShareBrain/components/BrainUsers/BrainUsers.tsx index 152ce23b6..46a152e33 100644 --- a/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/components/ShareBrain/components/BrainUsers/BrainUsers.tsx +++ b/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/components/ShareBrain/components/BrainUsers/BrainUsers.tsx @@ -23,7 +23,7 @@ export const BrainUsers = ({ brainId }: BrainUsersProps): JSX.Element => { diff --git a/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/components/ShareBrain/components/BrainUsers/components/BrainUser/BrainUser.tsx b/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/components/ShareBrain/components/BrainUsers/components/BrainUser/BrainUser.tsx index a6f29f3fc..eb79fc8d7 100644 --- a/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/components/ShareBrain/components/BrainUsers/components/BrainUser/BrainUser.tsx +++ b/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/components/ShareBrain/components/BrainUsers/components/BrainUser/BrainUser.tsx @@ -11,14 +11,14 @@ import { availableRoles } from "../../../../types"; type BrainUserProps = { email: string; - rights: BrainRoleType; + role: BrainRoleType; brainId: string; fetchBrainUsers: () => Promise; }; export const BrainUser = ({ email, - rights, + role, brainId, fetchBrainUsers, }: BrainUserProps): JSX.Element => { @@ -30,7 +30,7 @@ export const BrainUser = ({ updateSelectedRole, } = useBrainUser({ fetchBrainUsers: fetchBrainUsers, - rights, + role, brainId, email, }); @@ -62,7 +62,7 @@ export const BrainUser = ({ onChange={(newRole) => void updateSelectedRole(newRole)} value={selectedRole} options={availableRoles} - readOnly={currentBrain?.rights !== "Owner" && selectedRole === "Owner"} + readOnly={currentBrain?.role !== "Owner" && selectedRole === "Owner"} />
); diff --git a/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/components/ShareBrain/components/BrainUsers/components/BrainUser/hooks/useBrainUser.ts b/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/components/ShareBrain/components/BrainUsers/components/BrainUser/hooks/useBrainUser.ts index fb9724768..9907730c8 100644 --- a/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/components/ShareBrain/components/BrainUsers/components/BrainUser/hooks/useBrainUser.ts +++ b/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/components/ShareBrain/components/BrainUsers/components/BrainUser/hooks/useBrainUser.ts @@ -9,7 +9,7 @@ import { BrainRoleType } from "../../../../../../../types"; type UseBrainUserProps = { fetchBrainUsers: () => Promise; - rights: BrainRoleType; + role: BrainRoleType; brainId: string; email: string; }; @@ -17,19 +17,19 @@ type UseBrainUserProps = { export const useBrainUser = ({ brainId, fetchBrainUsers, - rights, + role, email, }: UseBrainUserProps) => { const { updateBrainAccess } = useBrainApi(); const { publish } = useToast(); - const [selectedRole, setSelectedRole] = useState(rights); + const [selectedRole, setSelectedRole] = useState(role); const [isRemovingAccess, setIsRemovingAccess] = useState(false); const { currentBrain } = useBrainContext(); const updateSelectedRole = async (newRole: BrainRoleType) => { setSelectedRole(newRole); try { await updateBrainAccess(brainId, email, { - rights: newRole, + role: newRole, }); publish({ variant: "success", text: `Updated ${email} to ${newRole}` }); void fetchBrainUsers(); @@ -58,7 +58,7 @@ export const useBrainUser = ({ setIsRemovingAccess(true); try { await updateBrainAccess(brainId, email, { - rights: null, + role: null, }); publish({ variant: "success", text: `Removed ${email} from brain` }); void fetchBrainUsers(); @@ -82,7 +82,7 @@ export const useBrainUser = ({ setIsRemovingAccess(false); } }; - const canRemoveAccess = currentBrain?.rights === "Owner"; + const canRemoveAccess = currentBrain?.role === "Owner"; return { isRemovingAccess, diff --git a/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/components/ShareBrain/components/UserToInvite.tsx b/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/components/ShareBrain/components/UserToInvite.tsx index 2795e46ae..704e4a41f 100644 --- a/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/components/ShareBrain/components/UserToInvite.tsx +++ b/frontend/lib/components/NavBar/components/NavItems/components/BrainsDropDown/components/BrainActions/components/ShareBrain/components/UserToInvite.tsx @@ -20,7 +20,7 @@ export const UserToInvite = ({ roleAssignation, }: UserToInviteProps): JSX.Element => { const [selectedRole, setSelectedRole] = useState( - roleAssignation.rights + roleAssignation.role ); const [email, setEmail] = useState(roleAssignation.email); const { currentBrain } = useBrainContext(); @@ -33,7 +33,7 @@ export const UserToInvite = ({ onChange({ ...roleAssignation, email, - rights: selectedRole, + role: selectedRole, }); }, [email, selectedRole]); @@ -60,7 +60,7 @@ export const UserToInvite = ({