diff --git a/backend/celery_worker.py b/backend/celery_worker.py index 4769d96ab45f..c6ef9eba2502 100644 --- a/backend/celery_worker.py +++ b/backend/celery_worker.py @@ -10,6 +10,9 @@ from models.notifications import NotificationsStatusEnum from models.settings import get_supabase_client from parsers.github import process_github +from repository.brain.update_brain_last_update_time import ( + update_brain_last_update_time, +) from repository.notification.update_notification import update_notification_by_id from utils.processors import filter_file @@ -98,6 +101,8 @@ def process_file_and_notify( message=str(notification_message), ), ) + update_brain_last_update_time(brain_id) + return True @@ -158,4 +163,5 @@ def process_crawl_and_notify( message=str(notification_message), ), ) + update_brain_last_update_time(brain_id) return True diff --git a/backend/models/databases/supabase/brains.py b/backend/models/databases/supabase/brains.py index 59eadffe33e4..de9ea8f80393 100644 --- a/backend/models/databases/supabase/brains.py +++ b/backend/models/databases/supabase/brains.py @@ -94,6 +94,11 @@ def get_public_brains(self) -> list[PublicBrain]: public_brains.append(brain) return public_brains + def update_brain_last_update_time(self, brain_id: UUID) -> None: + self.db.table("brains").update({"last_update": "now()"}).match( + {"brain_id": brain_id} + ).execute() + def get_brain_for_user(self, user_id, brain_id) -> MinimalBrainEntity | None: response = ( self.db.from_("brains_users") diff --git a/backend/repository/brain/update_brain.py b/backend/repository/brain/update_brain.py index 89722c8002c0..467d59ad803f 100644 --- a/backend/repository/brain/update_brain.py +++ b/backend/repository/brain/update_brain.py @@ -3,9 +3,16 @@ from models import BrainEntity, get_supabase_db from models.databases.supabase.brains import BrainUpdatableProperties +from repository.brain.update_brain_last_update_time import update_brain_last_update_time + def update_brain_by_id(brain_id: UUID, brain: BrainUpdatableProperties) -> BrainEntity: """Update a prompt by id""" supabase_db = get_supabase_db() - return supabase_db.update_brain_by_id(brain_id, brain) # type: ignore + brain_update_answer = supabase_db.update_brain_by_id(brain_id, brain) + if brain_update_answer is None: + raise Exception("Brain not found") + + update_brain_last_update_time(brain_id) + return brain_update_answer diff --git a/backend/repository/brain/update_brain_last_update_time.py b/backend/repository/brain/update_brain_last_update_time.py new file mode 100644 index 000000000000..98945e3126fd --- /dev/null +++ b/backend/repository/brain/update_brain_last_update_time.py @@ -0,0 +1,8 @@ +from uuid import UUID + +from models.settings import get_supabase_db + + +def update_brain_last_update_time(brain_id: UUID): + supabase_db = get_supabase_db() + supabase_db.update_brain_last_update_time(brain_id) diff --git a/frontend/app/brains-management/[brainId]/components/BrainManagementTabs/BrainManagementTabs.tsx b/frontend/app/brains-management/[brainId]/components/BrainManagementTabs/BrainManagementTabs.tsx index 9f3bc287410d..cc47740a2d9a 100644 --- a/frontend/app/brains-management/[brainId]/components/BrainManagementTabs/BrainManagementTabs.tsx +++ b/frontend/app/brains-management/[brainId]/components/BrainManagementTabs/BrainManagementTabs.tsx @@ -1,12 +1,15 @@ +/* eslint-disable max-lines */ import { Content, List, Root } from "@radix-ui/react-tabs"; import { useTranslation } from "react-i18next"; import Button from "@/lib/components/ui/Button"; +import { useBrainContext } from "@/lib/context/BrainProvider/hooks/useBrainContext"; import { BrainTabTrigger, KnowledgeTab, PeopleTab } from "./components"; import ConfirmationDeleteModal from "./components/Modals/ConfirmationDeleteModal"; import { SettingsTab } from "./components/SettingsTab/SettingsTab"; import { useBrainManagementTabs } from "./hooks/useBrainManagementTabs"; +import { isUserBrainOwner } from "./utils/canManageBrain"; export const BrainManagementTabs = (): JSX.Element => { const { t } = useTranslation(["translation", "config", "delete_brain"]); @@ -19,13 +22,21 @@ export const BrainManagementTabs = (): JSX.Element => { setIsDeleteModalOpen, brain, } = useBrainManagementTabs(); - - const isPubliclyAccessible = brain?.status === "public"; + const { allBrains } = useBrainContext(); if (brainId === undefined) { return
; } + const isCurrentUserBrainOwner = isUserBrainOwner({ + brainId, + userAccessibleBrains: allBrains, + }); + + const isPublicBrain = brain?.status === "public"; + + const hasEditRights = !isPublicBrain || isCurrentUserBrainOwner; + return ( { value="settings" onChange={setSelectedTab} /> - {!isPubliclyAccessible && ( + {hasEditRights && ( <> {
- {isPubliclyAccessible && ( + {isPublicBrain && ( {t("brain:public_brain_label")} @@ -80,7 +91,7 @@ export const SettingsTab = ({ brainId }: SettingsTabProps): JSX.Element => { isLoading={isSettingAsDefault} onClick={() => void setAsDefaultBrainHandler()} type="button" - disabled={isPubliclyAccessible} + disabled={!hasEditRights} > {t("setDefaultBrain", { ns: "brain" })} @@ -93,7 +104,7 @@ export const SettingsTab = ({ brainId }: SettingsTabProps): JSX.Element => { placeholder={t("brainDescriptionPlaceholder", { ns: "brain" })} autoComplete="off" className="flex-1 m-3" - disabled={isPubliclyAccessible} + disabled={!hasEditRights} {...register("description")} /> @@ -102,7 +113,7 @@ export const SettingsTab = ({ brainId }: SettingsTabProps): JSX.Element => { placeholder={t("openAiKeyPlaceholder", { ns: "config" })} autoComplete="off" className="flex-1" - disabled={isPubliclyAccessible} + disabled={!hasEditRights} {...register("openAiKey")} />
@@ -111,7 +122,7 @@ export const SettingsTab = ({ brainId }: SettingsTabProps): JSX.Element => {