Skip to content

Commit

Permalink
feat: display brain status on settings page (#1221)
Browse files Browse the repository at this point in the history
* feat: update GET/brains return status

* feat: add public tag on brain list

* feat: add public tag for public brain on brain settings tab

* feat: hide over tab when brain access is public
  • Loading branch information
mamadoudicko authored Sep 20, 2023
1 parent d8e1887 commit 1593c33
Show file tree
Hide file tree
Showing 14 changed files with 139 additions and 51 deletions.
1 change: 1 addition & 0 deletions backend/models/brain_entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,4 @@ class MinimalBrainEntity(BaseModel):
id: UUID
name: str
rights: RoleEnum
status: str
6 changes: 4 additions & 2 deletions backend/models/databases/supabase/brains.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def create_brain(self, brain: CreateBrainProperties):
def get_user_brains(self, user_id) -> list[MinimalBrainEntity]:
response = (
self.db.from_("brains_users")
.select("id:brain_id, rights, brains (id: brain_id, name)")
.select("id:brain_id, rights, brains (id: brain_id, name, status)")
.filter("user_id", "eq", user_id)
.execute()
)
Expand All @@ -69,6 +69,7 @@ def get_user_brains(self, user_id) -> list[MinimalBrainEntity]:
id=item["brains"]["id"],
name=item["brains"]["name"],
rights=item["rights"],
status=item["brains"]["status"],
)
)
user_brains[-1].rights = item["rights"]
Expand All @@ -77,7 +78,7 @@ def get_user_brains(self, user_id) -> list[MinimalBrainEntity]:
def get_brain_for_user(self, user_id, brain_id) -> MinimalBrainEntity | None:
response = (
self.db.from_("brains_users")
.select("id:brain_id, rights, brains (id: brain_id, name)")
.select("id:brain_id, rights, brains (id: brain_id, status, name)")
.filter("user_id", "eq", user_id)
.filter("brain_id", "eq", brain_id)
.execute()
Expand All @@ -90,6 +91,7 @@ def get_brain_for_user(self, user_id, brain_id) -> MinimalBrainEntity | None:
id=brain_data["brains"]["id"],
name=brain_data["brains"]["name"],
rights=brain_data["rights"],
status=brain_data["brains"]["status"],
)

def get_brain_details(self, brain_id):
Expand Down
5 changes: 3 additions & 2 deletions backend/repository/brain/get_user_brains.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
from uuid import UUID

from models import BrainEntity, get_supabase_db
from models import get_supabase_db
from models.brain_entity import MinimalBrainEntity


def get_user_brains(user_id: UUID) -> list[BrainEntity]:
def get_user_brains(user_id: UUID) -> list[MinimalBrainEntity]:
supabase_db = get_supabase_db()
results = supabase_db.get_user_brains(user_id) # type: ignore

Expand Down
5 changes: 4 additions & 1 deletion backend/routes/brain_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
update_brain_by_id,
)
from repository.prompt import delete_prompt_by_id, get_prompt_by_id

from routes.authorizations.brain_authorization import has_brain_authorization
from routes.authorizations.types import RoleEnum

Expand All @@ -31,7 +32,9 @@

# get all brains
@brain_router.get("/brains/", dependencies=[Depends(AuthBearer())], tags=["Brain"])
async def brain_endpoint(current_user: UserIdentity = Depends(get_current_user)):
async def brain_endpoint(
current_user: UserIdentity = Depends(get_current_user),
):
"""
Retrieve all brains for the current user.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
import Link from "next/link";
import { useTranslation } from "react-i18next";
import { FaBrain } from "react-icons/fa";

import { Chip } from "@/lib/components/ui/Chip";
import { MinimalBrainForUser } from "@/lib/context/BrainProvider/types";
import { cn } from "@/lib/utils";

import { useBrainListItem } from "./hooks/useBrainListItem";

interface BrainsListItemProps {
type BrainsListItemProps = {
brain: MinimalBrainForUser;
}

};
export const BrainListItem = ({ brain }: BrainsListItemProps): JSX.Element => {
const { selected } = useBrainListItem(brain);
const { t } = useTranslation("brain");

return (
<div
Expand All @@ -29,15 +31,20 @@ export const BrainListItem = ({ brain }: BrainsListItemProps): JSX.Element => {
href={`/brains-management/${brain.id}`}
key={brain.id}
>
<div className="flex items-center gap-2">
<FaBrain className="text-xl" />
<p>{brain.name}</p>
<div className="flex flex-row flex-1">
<div className="flex items-center gap-2">
<FaBrain className="text-xl" />
<p>{brain.name}</p>
</div>
{brain.status === "public" && (
<Chip className="ml-3">{t("public_brain_label")}</Chip>
)}
</div>
</Link>

<div
aria-hidden
className="not-sr-only absolute left-1/2 top-0 bottom-0 right-0 bg-gradient-to-r from-transparent to-white dark:to-black pointer-events-none"
className="not-sr-only absolute left-1/2 top-0 bottom-0 right-0 bg-gradient-to-r dark:to-black pointer-events-none"
></div>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,11 @@ export const BrainManagementTabs = (): JSX.Element => {
handleDeleteBrain,
isDeleteModalOpen,
setIsDeleteModalOpen,
brain,
} = useBrainManagementTabs();

const isPubliclyAccessible = brain?.status === "public";

if (brainId === undefined) {
return <div />;
}
Expand All @@ -38,21 +41,25 @@ export const BrainManagementTabs = (): JSX.Element => {
value="settings"
onChange={setSelectedTab}
/>
<BrainTabTrigger
selected={selectedTab === "people"}
label={t("people", { ns: "config" })}
value="people"
onChange={setSelectedTab}
/>
<BrainTabTrigger
selected={selectedTab === "knowledge"}
label={t("knowledge", { ns: "config" })}
value="knowledge"
onChange={setSelectedTab}
/>
{!isPubliclyAccessible && (
<>
<BrainTabTrigger
selected={selectedTab === "people"}
label={t("people", { ns: "config" })}
value="people"
onChange={setSelectedTab}
/>
<BrainTabTrigger
selected={selectedTab === "knowledge"}
label={t("knowledge", { ns: "config" })}
value="knowledge"
onChange={setSelectedTab}
/>
</>
)}
</List>

<div className="flex-1 p-4 md:p-20">
<div className="flex-1 p-4 md:p-20 md:pt-0">
<Content value="settings">
<SettingsTab brainId={brainId} />
</Content>
Expand All @@ -66,6 +73,7 @@ export const BrainManagementTabs = (): JSX.Element => {

<div className="flex justify-center mt-4">
<Button
disabled={isPubliclyAccessible}
className="px-8 md:px-20 py-2 bg-red-500 text-white rounded-md"
onClick={() => setIsDeleteModalOpen(true)}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { useTranslation } from "react-i18next";
import { FaSpinner } from "react-icons/fa";

import Button from "@/lib/components/ui/Button";
import { Chip } from "@/lib/components/ui/Chip";
import { Divider } from "@/lib/components/ui/Divider";
import Field from "@/lib/components/ui/Field";
import { TextArea } from "@/lib/components/ui/TextArea";
Expand All @@ -23,7 +24,6 @@ export const SettingsTab = ({ brainId }: SettingsTabProps): JSX.Element => {
const {
handleSubmit,
register,

temperature,
maxTokens,
model,
Expand All @@ -36,8 +36,11 @@ export const SettingsTab = ({ brainId }: SettingsTabProps): JSX.Element => {
pickPublicPrompt,
removeBrainPrompt,
accessibleModels,
brain,
} = useSettingsTab({ brainId });

const isPubliclyAccessible = brain?.status === "public";

return (
<form
onSubmit={(e) => {
Expand All @@ -47,39 +50,50 @@ export const SettingsTab = ({ brainId }: SettingsTabProps): JSX.Element => {
className="my-10 mb-0 flex flex-col items-center gap-2"
ref={formRef}
>
<div className="flex flex-row flex-1 justify-between w-full">
<div className="flex flex-row flex-1 justify-between w-full items-end">
<div>
<Field
label={t("brainName", { ns: "brain" })}
placeholder={t("brainNamePlaceholder", { ns: "brain" })}
autoComplete="off"
className="flex-1"
required
disabled={isPubliclyAccessible}
{...register("name")}
/>
</div>

<div className="mt-4">
{isDefaultBrain ? (
<div className="border rounded-lg border-dashed border-black dark:border-white bg-white dark:bg-black text-black dark:text-white focus:bg-black dark:focus:bg-white dark dark focus:text-white dark:focus:text-black transition-colors py-2 px-4 shadow-none">
{t("defaultBrain", { ns: "brain" })}
</div>
) : (
<Button
variant={"secondary"}
isLoading={isSettingAsDefault}
onClick={() => void setAsDefaultBrainHandler()}
type="button"
>
{t("setDefaultBrain", { ns: "brain" })}
</Button>
)}
<div className="flex flex-1 items-center flex-col">
{isPubliclyAccessible && (
<Chip className="mb-3 bg-purple-600 text-white w-full">
{t("brain:public_brain_label")}
</Chip>
)}
{isDefaultBrain ? (
<div className="border rounded-lg border-dashed border-black dark:border-white bg-white dark:bg-black text-black dark:text-white focus:bg-black dark:focus:bg-white dark dark focus:text-white dark:focus:text-black transition-colors py-2 px-4 shadow-none">
{t("defaultBrain", { ns: "brain" })}
</div>
) : (
<Button
variant={"secondary"}
isLoading={isSettingAsDefault}
onClick={() => void setAsDefaultBrainHandler()}
type="button"
disabled={isPubliclyAccessible}
>
{t("setDefaultBrain", { ns: "brain" })}
</Button>
)}
</div>
</div>
</div>
<TextArea
label={t("brainDescription", { ns: "brain" })}
placeholder={t("brainDescriptionPlaceholder", { ns: "brain" })}
autoComplete="off"
className="flex-1 m-3"
disabled={isPubliclyAccessible}
{...register("description")}
/>
<Divider text={t("modelSection", { ns: "config" })} />
Expand All @@ -88,6 +102,7 @@ export const SettingsTab = ({ brainId }: SettingsTabProps): JSX.Element => {
placeholder={t("openAiKeyPlaceholder", { ns: "config" })}
autoComplete="off"
className="flex-1"
disabled={isPubliclyAccessible}
{...register("openAiKey")}
/>
<fieldset className="w-full flex flex-col mt-2">
Expand All @@ -96,6 +111,7 @@ export const SettingsTab = ({ brainId }: SettingsTabProps): JSX.Element => {
</label>
<select
id="model"
disabled={isPubliclyAccessible}
{...register("model")}
className="px-5 py-2 dark:bg-gray-700 bg-gray-200 rounded-md"
onChange={() => {
Expand All @@ -120,6 +136,7 @@ export const SettingsTab = ({ brainId }: SettingsTabProps): JSX.Element => {
max="1"
step="0.01"
value={temperature}
disabled={isPubliclyAccessible}
{...register("temperature")}
/>
</fieldset>
Expand All @@ -132,33 +149,45 @@ export const SettingsTab = ({ brainId }: SettingsTabProps): JSX.Element => {
min="10"
max={defineMaxTokens(model)}
value={maxTokens}
disabled={isPubliclyAccessible}
{...register("maxTokens")}
/>
</fieldset>
<div className="flex w-full justify-end py-4">
<SaveButton handleSubmit={handleSubmit} />
<SaveButton
disabled={isPubliclyAccessible}
handleSubmit={handleSubmit}
/>
</div>
<Divider text={t("customPromptSection", { ns: "config" })} />
<PublicPrompts onSelect={pickPublicPrompt} />
{!isPubliclyAccessible && <PublicPrompts onSelect={pickPublicPrompt} />}
<Field
label={t("promptName", { ns: "config" })}
placeholder={t("promptNamePlaceholder", { ns: "config" })}
autoComplete="off"
className="flex-1"
disabled={isPubliclyAccessible}
{...register("prompt.title")}
/>
<TextArea
label={t("promptContent", { ns: "config" })}
placeholder={t("promptContentPlaceholder", { ns: "config" })}
autoComplete="off"
className="flex-1"
disabled={isPubliclyAccessible}
{...register("prompt.content")}
/>
<div className="flex w-full justify-end py-4">
<SaveButton handleSubmit={handleSubmit} />
<SaveButton
disabled={isPubliclyAccessible}
handleSubmit={handleSubmit}
/>
</div>
{promptId !== "" && (
<Button disabled={isUpdating} onClick={() => void removeBrainPrompt()}>
<Button
disabled={isUpdating || isPubliclyAccessible}
onClick={() => void removeBrainPrompt()}
>
{t("removePrompt", { ns: "config" })}
</Button>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,7 @@ export const useSettingsTab = ({ brainId }: UseSettingsTabProps) => {
return {
handleSubmit,
register,

brain,
model,
temperature,
maxTokens,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { useQuery } from "@tanstack/react-query";
import { UUID } from "crypto";
import { useParams, useRouter } from "next/navigation";
import { useEffect, useState } from "react";

import { getBrainDataKey } from "@/lib/api/brain/config";
import { useBrainApi } from "@/lib/api/brain/useBrainApi";
import { useBrainContext } from "@/lib/context/BrainProvider/hooks/useBrainContext";

import { BrainManagementTab } from "../types";
Expand All @@ -18,6 +21,7 @@ export const useBrainManagementTabs = () => {
setSelectedTab(targetedTab);
}
}, []);
const { getBrain } = useBrainApi();

const { deleteBrain, setCurrentBrainId } = useBrainContext();
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
Expand All @@ -27,6 +31,12 @@ export const useBrainManagementTabs = () => {

const brainId = params?.brainId as UUID | undefined;

const { data: brain } = useQuery({
queryKey: [getBrainDataKey(brainId!)],
queryFn: () => getBrain(brainId!),
enabled: brainId !== undefined,
});

const handleDeleteBrain = () => {
if (brainId === undefined) {
return;
Expand All @@ -44,5 +54,6 @@ export const useBrainManagementTabs = () => {
handleDeleteBrain,
isDeleteModalOpen,
setIsDeleteModalOpen,
brain,
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ export const mapBackendMinimalBrainToMinimalBrain = (
id: backendMinimalBrain.id,
name: backendMinimalBrain.name,
role: backendMinimalBrain.rights,
status: backendMinimalBrain.status,
});
Loading

0 comments on commit 1593c33

Please sign in to comment.