fix(frontend): only owner can access knowledge and edit brain snippet (#3073)

# Description

Please include a summary of the changes and the related issue. Please
also include relevant motivation and context.

## Checklist before requesting a review

Please delete options that are not relevant.

- [ ] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my code
- [ ] I have commented hard-to-understand areas
- [ ] I have ideally added tests that prove my fix is effective or that
my feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged

## Screenshots (if appropriate):
This commit is contained in:
Antoine Dewez 2024-08-23 12:33:18 +02:00 committed by GitHub
parent 0b33c3f193
commit 5e59e707cc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 53 additions and 38 deletions

View File

@ -1,7 +1,7 @@
/* eslint-disable max-lines */ /* eslint-disable max-lines */
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import { useEffect, useState } from "react"; import { useState } from "react";
import { Icon } from "@/lib/components/ui/Icon/Icon"; import { Icon } from "@/lib/components/ui/Icon/Icon";
import { LoaderIcon } from "@/lib/components/ui/LoaderIcon/LoaderIcon"; import { LoaderIcon } from "@/lib/components/ui/LoaderIcon/LoaderIcon";
@ -22,27 +22,20 @@ export const BrainManagementTabs = (): JSX.Element => {
const { allKnowledge } = useAddedKnowledge({ brainId: brainId ?? undefined }); const { allKnowledge } = useAddedKnowledge({ brainId: brainId ?? undefined });
const router = useRouter(); const router = useRouter();
const { brain, isLoading } = useBrainFetcher({ const { isLoading } = useBrainFetcher({
brainId, brainId,
}); });
const knowledgeTabDisabled = (): boolean => {
return (
!hasEditRights ||
(brain?.integration_description?.max_files === 0 &&
brain.brain_type !== "doc")
);
};
const brainManagementTabs: Tab[] = [ const brainManagementTabs: Tab[] = [
{ {
label: `Knowledge${allKnowledge.length > 1 ? "s" : ""} (${ label: hasEditRights
allKnowledge.length ? `Knowledge${allKnowledge.length > 1 ? "s" : ""} (${
})`, allKnowledge.length
})`
: "Knowledge",
isSelected: selectedTab === "Knowledge", isSelected: selectedTab === "Knowledge",
onClick: () => setSelectedTab("Knowledge"), onClick: () => setSelectedTab("Knowledge"),
iconName: "file", iconName: "file",
disabled: knowledgeTabDisabled(),
}, },
{ {
label: "Settings", label: "Settings",
@ -59,10 +52,6 @@ export const BrainManagementTabs = (): JSX.Element => {
}, },
]; ];
useEffect(() => {
brainManagementTabs[2].disabled = knowledgeTabDisabled();
}, [hasEditRights]);
if (!brainId) { if (!brainId) {
return <div />; return <div />;
} }
@ -89,7 +78,9 @@ export const BrainManagementTabs = (): JSX.Element => {
<Tabs tabList={brainManagementTabs} /> <Tabs tabList={brainManagementTabs} />
</div> </div>
</div> </div>
{selectedTab === "Settings" && <SettingsTab brainId={brainId} />} {selectedTab === "Settings" && (
<SettingsTab brainId={brainId} hasEditRights={hasEditRights} />
)}
{selectedTab === "People" && <PeopleTab brainId={brainId} />} {selectedTab === "People" && <PeopleTab brainId={brainId} />}
{selectedTab === "Knowledge" && ( {selectedTab === "Knowledge" && (
<KnowledgeTab <KnowledgeTab

View File

@ -20,12 +20,26 @@ type KnowledgeTabProps = {
export const KnowledgeTab = ({ export const KnowledgeTab = ({
brainId, brainId,
allKnowledge, allKnowledge,
hasEditRights,
}: KnowledgeTabProps): JSX.Element => { }: KnowledgeTabProps): JSX.Element => {
const { isPending } = useAddedKnowledge({ const { isPending } = useAddedKnowledge({
brainId, brainId,
}); });
const { setShouldDisplayFeedCard } = useKnowledgeToFeedContext(); const { setShouldDisplayFeedCard } = useKnowledgeToFeedContext();
if (hasEditRights) {
return (
<div className={styles.knowledge_tab_container}>
<div className={styles.knowledge_tab_wrapper}>
<MessageInfoBox type="warning">
You don&apos;t have permission to access the knowledge in this
brain.
</MessageInfoBox>
</div>
</div>
);
}
if (isPending) { if (isPending) {
return <LoaderIcon size="big" color="accent" />; return <LoaderIcon size="big" color="accent" />;
} }

View File

@ -61,7 +61,6 @@
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
cursor: pointer;
font-size: Typography.$very_large; font-size: Typography.$very_large;
} }
@ -72,6 +71,12 @@
font-size: Typography.$small; font-size: Typography.$small;
gap: Spacings.$spacing03; gap: Spacings.$spacing03;
} }
&.clickable {
.brain_snippet {
cursor: pointer;
}
}
} }
.general_information { .general_information {

View File

@ -14,7 +14,6 @@ import { GeneralInformation } from "./components/GeneralInformation/GeneralInfor
import { ModelSelection } from "./components/ModelSelection/ModelSelection"; import { ModelSelection } from "./components/ModelSelection/ModelSelection";
import { Prompt } from "./components/Prompt/Prompt"; import { Prompt } from "./components/Prompt/Prompt";
import { useBrainFormState } from "./hooks/useBrainFormState"; import { useBrainFormState } from "./hooks/useBrainFormState";
import { usePermissionsController } from "./hooks/usePermissionsController";
import { UsePromptProps } from "./hooks/usePrompt"; import { UsePromptProps } from "./hooks/usePrompt";
import { useSettingsTab } from "./hooks/useSettingsTab"; import { useSettingsTab } from "./hooks/useSettingsTab";
@ -22,20 +21,18 @@ import { useBrainFetcher } from "../../hooks/useBrainFetcher";
type SettingsTabProps = { type SettingsTabProps = {
brainId: UUID; brainId: UUID;
hasEditRights: boolean;
}; };
export const SettingsTabContent = ({ export const SettingsTabContent = ({
brainId, brainId,
hasEditRights,
}: SettingsTabProps): JSX.Element => { }: SettingsTabProps): JSX.Element => {
const { t } = useTranslation(["translation", "brain", "config"]); const { t } = useTranslation(["translation", "brain", "config"]);
const [editSnippet, setEditSnippet] = useState<boolean>(false); const [editSnippet, setEditSnippet] = useState<boolean>(false);
const [snippetColor, setSnippetColor] = useState<string>(""); const [snippetColor, setSnippetColor] = useState<string>("");
const [snippetEmoji, setSnippetEmoji] = useState<string>(""); const [snippetEmoji, setSnippetEmoji] = useState<string>("");
const { hasEditRights } = usePermissionsController({
brainId,
});
const { brain } = useBrainFetcher({ const { brain } = useBrainFetcher({
brainId, brainId,
}); });
@ -81,7 +78,11 @@ export const SettingsTabContent = ({
<div className={styles.inputs_wrapper}> <div className={styles.inputs_wrapper}>
<div className={styles.brain_snippet_wrapper}> <div className={styles.brain_snippet_wrapper}>
{editSnippet && ( {editSnippet && (
<div className={styles.edit_snippet}> <div
className={`${styles.edit_snippet} ${
hasEditRights ? styles.clickable : ""
}`}
>
<BrainSnippet <BrainSnippet
setVisible={setEditSnippet} setVisible={setEditSnippet}
initialColor={brain.snippet_color} initialColor={brain.snippet_color}
@ -98,26 +99,27 @@ export const SettingsTabContent = ({
className={styles.brain_snippet} className={styles.brain_snippet}
style={{ backgroundColor: snippetColor }} style={{ backgroundColor: snippetColor }}
onClick={() => { onClick={() => {
if (!editSnippet) { if (!editSnippet && hasEditRights) {
setEditSnippet(true); setEditSnippet(true);
} }
}} }}
> >
<span>{snippetEmoji}</span> <span>{snippetEmoji}</span>
</div> </div>
<QuivrButton {hasEditRights && (
label="Edit" <QuivrButton
iconName="edit" label="Edit"
color="primary" iconName="edit"
onClick={() => setEditSnippet(true)} color="primary"
small={true} onClick={() => setEditSnippet(true)}
/> small={true}
/>
)}
</div> </div>
<div className={styles.general_information}> <div className={styles.general_information}>
<GeneralInformation hasEditRights={hasEditRights} /> <GeneralInformation hasEditRights={hasEditRights} />
</div> </div>
{(!!brain.integration_description?.allow_model_change || {brain.brain_type === "doc" && (
brain.brain_type === "doc") && (
<div className={styles.model_information}> <div className={styles.model_information}>
<ModelSelection <ModelSelection
accessibleModels={accessibleModels} accessibleModels={accessibleModels}
@ -164,12 +166,15 @@ export const SettingsTabContent = ({
); );
}; };
export const SettingsTab = ({ brainId }: SettingsTabProps): JSX.Element => { export const SettingsTab = ({
brainId,
hasEditRights,
}: SettingsTabProps): JSX.Element => {
const methods = useForm<Brain>(); const methods = useForm<Brain>();
return ( return (
<FormProvider {...methods}> <FormProvider {...methods}>
<SettingsTabContent brainId={brainId} /> <SettingsTabContent brainId={brainId} hasEditRights={hasEditRights} />
</FormProvider> </FormProvider>
); );
}; };