mirror of
https://github.com/QuivrHQ/quivr.git
synced 2024-12-14 17:03:29 +03:00
feat(frontend): first custom brain live (#2226)
# 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:
parent
ec5679072f
commit
b09878f332
@ -205,7 +205,7 @@ def get_user_invitation(
|
||||
detail="You have not been invited to this brain",
|
||||
)
|
||||
|
||||
brain_details = brain_service.get_brain_details(brain_id)
|
||||
brain_details = brain_service.get_brain_details(brain_id, current_user.id)
|
||||
|
||||
if brain_details is None:
|
||||
raise HTTPException(
|
||||
|
@ -26,8 +26,9 @@ export const KnowledgeToFeed = ({
|
||||
const brainsWithUploadRights = formatMinimalBrainsToSelectComponentInput(
|
||||
useMemo(
|
||||
() =>
|
||||
allBrains.filter((brain) =>
|
||||
requiredRolesForUpload.includes(brain.role)
|
||||
allBrains.filter(
|
||||
(brain) =>
|
||||
requiredRolesForUpload.includes(brain.role) && !!brain.max_files
|
||||
),
|
||||
[allBrains]
|
||||
)
|
||||
|
@ -14,6 +14,7 @@ export const QADisplay = ({ content }: QADisplayProps): JSX.Element => {
|
||||
brain_name,
|
||||
prompt_title,
|
||||
metadata,
|
||||
brain_id,
|
||||
} = content;
|
||||
|
||||
return (
|
||||
@ -31,6 +32,7 @@ export const QADisplay = ({ content }: QADisplayProps): JSX.Element => {
|
||||
text={assistant}
|
||||
brainName={brain_name}
|
||||
promptName={prompt_title}
|
||||
brainId={brain_id}
|
||||
metadata={metadata} // eslint-disable-line @typescript-eslint/no-unsafe-assignment
|
||||
/>
|
||||
</>
|
||||
|
@ -19,11 +19,19 @@ type MessageRowProps = {
|
||||
metadata?: {
|
||||
sources?: Source[];
|
||||
};
|
||||
brainId?: string;
|
||||
};
|
||||
|
||||
export const MessageRow = React.forwardRef(
|
||||
(
|
||||
{ speaker, text, brainName, promptName, children }: MessageRowProps,
|
||||
{
|
||||
speaker,
|
||||
text,
|
||||
brainName,
|
||||
promptName,
|
||||
children,
|
||||
brainId,
|
||||
}: MessageRowProps,
|
||||
ref: React.Ref<HTMLDivElement>
|
||||
) => {
|
||||
const { handleCopy, isUserSpeaker } = useMessageRow({
|
||||
@ -42,7 +50,7 @@ export const MessageRow = React.forwardRef(
|
||||
>
|
||||
{!isUserSpeaker ? (
|
||||
<div className={styles.message_header}>
|
||||
<QuestionBrain brainName={brainName} />
|
||||
<QuestionBrain brainName={brainName} brainId={brainId} />
|
||||
<QuestionPrompt promptName={promptName} />
|
||||
</div>
|
||||
) : (
|
||||
|
@ -1,22 +1,51 @@
|
||||
import { Fragment } from "react";
|
||||
import Image from "next/image";
|
||||
import { Fragment, useEffect, useState } from "react";
|
||||
|
||||
import { useBrainApi } from "@/lib/api/brain/useBrainApi";
|
||||
import Icon from "@/lib/components/ui/Icon/Icon";
|
||||
|
||||
import styles from "./QuestionBrain.module.scss";
|
||||
|
||||
type QuestionBrainProps = {
|
||||
brainName?: string | null;
|
||||
brainId?: string;
|
||||
};
|
||||
export const QuestionBrain = ({
|
||||
brainName,
|
||||
brainId,
|
||||
}: QuestionBrainProps): JSX.Element => {
|
||||
const [brainLogoUrl, setBrainLogoUrl] = useState<string | undefined>(
|
||||
undefined
|
||||
);
|
||||
|
||||
const { getBrain } = useBrainApi();
|
||||
|
||||
const getBrainLogoUrl = async () => {
|
||||
if (brainId) {
|
||||
try {
|
||||
const brain = await getBrain(brainId.toString());
|
||||
setBrainLogoUrl(brain?.integration_description?.integration_logo_url);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
void getBrainLogoUrl();
|
||||
}, [brainId]);
|
||||
|
||||
if (brainName === undefined || brainName === null) {
|
||||
return <Fragment />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div data-testid="brain-tags" className={styles.brain_name_wrapper}>
|
||||
{brainLogoUrl ? (
|
||||
<Image src={brainLogoUrl} alt="brainLogo" width={18} height={18} />
|
||||
) : (
|
||||
<Icon name="brain" color="primary" size="normal" />
|
||||
)}
|
||||
<span>{brainName}</span>
|
||||
</div>
|
||||
);
|
||||
|
@ -49,6 +49,7 @@ const SelectedChatPage = (): JSX.Element => {
|
||||
setShouldDisplayFeedCard(true);
|
||||
},
|
||||
iconName: "uploadFile",
|
||||
hidden: !currentBrain?.max_files,
|
||||
},
|
||||
{
|
||||
label: "Manage current brain",
|
||||
|
@ -25,7 +25,6 @@ export const BrainManagementTabs = (): JSX.Element => {
|
||||
isDeleteOrUnsubscribeModalOpened,
|
||||
setIsDeleteOrUnsubscribeModalOpened,
|
||||
hasEditRights,
|
||||
isPublicBrain,
|
||||
isOwnedByCurrentUser,
|
||||
isDeleteOrUnsubscribeRequestPending,
|
||||
} = useBrainManagementTabs();
|
||||
@ -57,14 +56,16 @@ export const BrainManagementTabs = (): JSX.Element => {
|
||||
<StyledTabsTrigger value="settings">
|
||||
{t("settings", { ns: "config" })}
|
||||
</StyledTabsTrigger>
|
||||
{(!isPublicBrain || hasEditRights) && (
|
||||
{hasEditRights && (
|
||||
<>
|
||||
<StyledTabsTrigger value="people">
|
||||
{t("people", { ns: "config" })}
|
||||
</StyledTabsTrigger>
|
||||
{brain?.brain_type === "doc" && (
|
||||
<StyledTabsTrigger value="knowledgeOrSecrets">
|
||||
{knowledgeOrSecretsTabLabel}
|
||||
</StyledTabsTrigger>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</TabsList>
|
||||
@ -76,12 +77,14 @@ export const BrainManagementTabs = (): JSX.Element => {
|
||||
<TabsContent value="people">
|
||||
<PeopleTab brainId={brainId} hasEditRights={hasEditRights} />
|
||||
</TabsContent>
|
||||
{brain?.brain_type === "doc" && (
|
||||
<TabsContent value="knowledgeOrSecrets">
|
||||
<KnowledgeOrSecretsTab
|
||||
brainId={brainId}
|
||||
hasEditRights={hasEditRights}
|
||||
/>
|
||||
</TabsContent>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="flex justify-center">
|
||||
|
@ -15,6 +15,8 @@ import { usePermissionsController } from "./hooks/usePermissionsController";
|
||||
import { UsePromptProps } from "./hooks/usePrompt";
|
||||
import { useSettingsTab } from "./hooks/useSettingsTab";
|
||||
|
||||
import { useBrainFetcher } from "../../hooks/useBrainFetcher";
|
||||
|
||||
type SettingsTabProps = {
|
||||
brainId: UUID;
|
||||
};
|
||||
@ -47,6 +49,10 @@ export const SettingsTabContent = ({
|
||||
brainId,
|
||||
});
|
||||
|
||||
const { brain } = useBrainFetcher({
|
||||
brainId,
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<form
|
||||
@ -65,18 +71,23 @@ export const SettingsTabContent = ({
|
||||
isSettingAsDefault={isSettingAsDefault}
|
||||
setAsDefaultBrainHandler={setAsDefaultBrainHandler}
|
||||
/>
|
||||
{brain?.brain_type === "doc" && (
|
||||
<>
|
||||
<Divider
|
||||
textClassName="font-semibold text-black w-full mx-1"
|
||||
separatorClassName="w-full"
|
||||
className="w-full my-10"
|
||||
text={t("modelSection", { ns: "config" })}
|
||||
/>
|
||||
|
||||
<ModelSelection
|
||||
accessibleModels={accessibleModels}
|
||||
hasEditRights={hasEditRights}
|
||||
brainId={brainId}
|
||||
handleSubmit={handleSubmit}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<Divider text={t("customPromptSection", { ns: "config" })} />
|
||||
<Prompt
|
||||
usePromptProps={promptProps}
|
||||
|
@ -1,17 +1,12 @@
|
||||
/* eslint max-lines:["error", 150] */
|
||||
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { LuStar } from "react-icons/lu";
|
||||
|
||||
import { ApiRequestDefinition } from "@/lib/components/ApiRequestDefinition";
|
||||
import Button from "@/lib/components/ui/Button";
|
||||
import { Chip } from "@/lib/components/ui/Chip";
|
||||
import Field from "@/lib/components/ui/Field";
|
||||
import { Radio } from "@/lib/components/ui/Radio";
|
||||
import { TextArea } from "@/lib/components/ui/TextArea";
|
||||
|
||||
import { useGeneralInformation } from "./hooks/useGeneralInformation";
|
||||
|
||||
import { useBrainFormState } from "../../hooks/useBrainFormState";
|
||||
|
||||
type GeneralInformationProps = {
|
||||
@ -27,18 +22,9 @@ export const GeneralInformation = (
|
||||
props: GeneralInformationProps
|
||||
): JSX.Element => {
|
||||
const { t } = useTranslation(["translation", "brain", "config"]);
|
||||
const {
|
||||
hasEditRights,
|
||||
isPublicBrain,
|
||||
isOwnedByCurrentUser,
|
||||
isDefaultBrain,
|
||||
isSettingAsDefault,
|
||||
setAsDefaultBrainHandler,
|
||||
} = props;
|
||||
const { hasEditRights, isPublicBrain, isOwnedByCurrentUser } = props;
|
||||
const { register } = useBrainFormState();
|
||||
|
||||
const { brainTypeOptions } = useGeneralInformation();
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 justify-between w-full items-end">
|
||||
@ -61,21 +47,6 @@ export const GeneralInformation = (
|
||||
{t("brain:public_brain_label")}
|
||||
</Chip>
|
||||
)}
|
||||
<div>
|
||||
{hasEditRights && (
|
||||
<Button
|
||||
variant={"secondary"}
|
||||
isLoading={isSettingAsDefault}
|
||||
onClick={() => void setAsDefaultBrainHandler()}
|
||||
type="button"
|
||||
className="bg-secondary text-primary border-none hover:bg-primary hover:text-white hover:disabled:text-primary disabled:bg-secondary disabled:text-primary disabled:cursor-not-allowed"
|
||||
disabled={isSettingAsDefault || isDefaultBrain}
|
||||
>
|
||||
<LuStar size={18} />
|
||||
{t("defaultBrain", { ns: "brain" })}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -89,15 +60,6 @@ export const GeneralInformation = (
|
||||
{...register("description")}
|
||||
/>
|
||||
|
||||
<div className="w-full mt-4">
|
||||
<Radio
|
||||
items={brainTypeOptions}
|
||||
label={t("knowledge_source_label", { ns: "brain" })}
|
||||
className="flex-1 justify-between w-[50%]"
|
||||
disabled={true}
|
||||
{...register("brain_type")}
|
||||
/>
|
||||
</div>
|
||||
<ApiRequestDefinition />
|
||||
</>
|
||||
);
|
||||
|
@ -11,6 +11,7 @@ import {
|
||||
|
||||
import {
|
||||
CreateBrainInput,
|
||||
IntegrationBrains,
|
||||
ListFilesProps,
|
||||
SubscriptionUpdatableProperties,
|
||||
UpdateBrainInput,
|
||||
@ -155,3 +156,10 @@ export const getDocsFromQuestion = async (
|
||||
)
|
||||
).data.docs;
|
||||
};
|
||||
|
||||
export const getIntegrationBrains = async (
|
||||
axiosInstance: AxiosInstance
|
||||
): Promise<IntegrationBrains[]> => {
|
||||
return (await axiosInstance.get<IntegrationBrains[]>(`/brains/integrations`))
|
||||
.data;
|
||||
};
|
||||
|
@ -51,6 +51,11 @@ export type ApiBrainDefinition = {
|
||||
jq_instructions: string;
|
||||
};
|
||||
|
||||
export type IntegrationSettings = {
|
||||
integration_id?: string;
|
||||
settings?: { [x: string]: object | undefined };
|
||||
};
|
||||
|
||||
export type CreateBrainInput = {
|
||||
name: string;
|
||||
description: string;
|
||||
@ -63,6 +68,17 @@ export type CreateBrainInput = {
|
||||
brain_definition?: Omit<ApiBrainDefinition, "brain_id">;
|
||||
brain_secrets_values?: Record<string, string>;
|
||||
connected_brains_ids?: UUID[];
|
||||
integration?: IntegrationSettings;
|
||||
};
|
||||
|
||||
export type IntegrationBrains = {
|
||||
id: UUID;
|
||||
integration_name: string;
|
||||
integration_logo_url: string;
|
||||
connections_settings: Record<string, unknown>;
|
||||
integration_type: "custom" | "sync";
|
||||
description: string;
|
||||
max_files: number;
|
||||
};
|
||||
|
||||
export type UpdateBrainInput = Partial<CreateBrainInput>;
|
||||
|
@ -9,6 +9,7 @@ import {
|
||||
getBrainUsers,
|
||||
getDefaultBrain,
|
||||
getDocsFromQuestion,
|
||||
getIntegrationBrains,
|
||||
getPublicBrains,
|
||||
setAsDefaultBrain,
|
||||
Subscription,
|
||||
@ -55,5 +56,6 @@ export const useBrainApi = () => {
|
||||
brainId: string,
|
||||
secrets: Record<string, string>
|
||||
) => updateBrainSecrets(brainId, secrets, axiosInstance),
|
||||
getIntegrationBrains: async () => getIntegrationBrains(axiosInstance),
|
||||
};
|
||||
};
|
||||
|
@ -12,4 +12,6 @@ export const mapBackendMinimalBrainToMinimalBrain = (
|
||||
status: backendMinimalBrain.status,
|
||||
brain_type: backendMinimalBrain.brain_type,
|
||||
description: backendMinimalBrain.description,
|
||||
integration_logo_url: backendMinimalBrain.integration_logo_url,
|
||||
max_files: backendMinimalBrain.max_files,
|
||||
});
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { useEffect } from "react";
|
||||
import { FormProvider, useForm } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
@ -6,17 +7,20 @@ import { addBrainDefaultValues } from "@/lib/config/defaultBrainConfig";
|
||||
|
||||
import styles from "./AddBrainModal.module.scss";
|
||||
import { useBrainCreationContext } from "./brainCreation-provider";
|
||||
import { BrainKnowledgeStep } from "./components/BrainKnowledgeStep/BrainKnowledgeStep";
|
||||
import { BrainMainInfosStep } from "./components/BrainMainInfosStep/BrainMainInfosStep";
|
||||
import { BrainTypeSelectionStep } from "./components/BrainTypeSelectionStep/BrainTypeSelectionStep";
|
||||
import { CreateBrainStep } from "./components/CreateBrainStep/CreateBrainStep";
|
||||
import { Stepper } from "./components/Stepper/Stepper";
|
||||
import { CreateBrainProps } from "./types/types";
|
||||
|
||||
export const AddBrainModal = (): JSX.Element => {
|
||||
const { t } = useTranslation(["translation", "brain", "config"]);
|
||||
|
||||
const { isBrainCreationModalOpened, setIsBrainCreationModalOpened } =
|
||||
useBrainCreationContext();
|
||||
const {
|
||||
isBrainCreationModalOpened,
|
||||
setIsBrainCreationModalOpened,
|
||||
setCurrentIntegrationBrain,
|
||||
} = useBrainCreationContext();
|
||||
|
||||
const defaultValues: CreateBrainProps = {
|
||||
...addBrainDefaultValues,
|
||||
@ -28,6 +32,10 @@ export const AddBrainModal = (): JSX.Element => {
|
||||
defaultValues,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
setCurrentIntegrationBrain(undefined);
|
||||
}, [isBrainCreationModalOpened]);
|
||||
|
||||
return (
|
||||
<FormProvider {...methods}>
|
||||
<Modal
|
||||
@ -45,7 +53,7 @@ export const AddBrainModal = (): JSX.Element => {
|
||||
<div className={styles.content_wrapper}>
|
||||
<BrainTypeSelectionStep />
|
||||
<BrainMainInfosStep />
|
||||
<BrainKnowledgeStep />
|
||||
<CreateBrainStep />
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
|
@ -1,10 +1,16 @@
|
||||
import { createContext, useContext, useState } from "react";
|
||||
|
||||
import { IntegrationBrains } from "@/lib/api/brain/types";
|
||||
|
||||
interface BrainCreationContextProps {
|
||||
isBrainCreationModalOpened: boolean;
|
||||
setIsBrainCreationModalOpened: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
creating: boolean;
|
||||
setCreating: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
currentIntegrationBrain: IntegrationBrains | undefined;
|
||||
setCurrentIntegrationBrain: React.Dispatch<
|
||||
React.SetStateAction<IntegrationBrains | undefined>
|
||||
>;
|
||||
}
|
||||
|
||||
export const BrainCreationContext = createContext<
|
||||
@ -18,6 +24,8 @@ export const BrainCreationProvider = ({
|
||||
}): JSX.Element => {
|
||||
const [isBrainCreationModalOpened, setIsBrainCreationModalOpened] =
|
||||
useState<boolean>(false);
|
||||
const [currentIntegrationBrain, setCurrentIntegrationBrain] =
|
||||
useState<IntegrationBrains>();
|
||||
const [creating, setCreating] = useState<boolean>(false);
|
||||
|
||||
return (
|
||||
@ -27,6 +35,8 @@ export const BrainCreationProvider = ({
|
||||
setIsBrainCreationModalOpened,
|
||||
creating,
|
||||
setCreating,
|
||||
currentIntegrationBrain,
|
||||
setCurrentIntegrationBrain,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
|
@ -1,35 +0,0 @@
|
||||
import { Checkbox } from "@/lib/components/ui/Checkbox";
|
||||
import { MinimalBrainForUser } from "@/lib/context/BrainProvider/types";
|
||||
|
||||
import { useConnectableBrain } from "./hooks/useConnectableBrain";
|
||||
|
||||
type ConnectableBrainProps = {
|
||||
brain: MinimalBrainForUser;
|
||||
};
|
||||
|
||||
export const ConnectableBrain = ({
|
||||
brain,
|
||||
}: ConnectableBrainProps): JSX.Element => {
|
||||
const { onCheckedChange } = useConnectableBrain();
|
||||
|
||||
return (
|
||||
<div className="flex flex-row items-center gap-2">
|
||||
<Checkbox
|
||||
className="text-white"
|
||||
onCheckedChange={(checked) =>
|
||||
onCheckedChange({
|
||||
brainId: brain.id,
|
||||
checked,
|
||||
})
|
||||
}
|
||||
id={`connected_brains_ids-${brain.id}`}
|
||||
/>
|
||||
<label
|
||||
htmlFor={`connected_brains_ids-${brain.id}`}
|
||||
className="text-md font-medium leading-none cursor-pointer"
|
||||
>
|
||||
{brain.name}
|
||||
</label>
|
||||
</div>
|
||||
);
|
||||
};
|
@ -1,35 +0,0 @@
|
||||
import { CheckedState } from "@radix-ui/react-checkbox";
|
||||
import { UUID } from "crypto";
|
||||
import { useFormContext } from "react-hook-form";
|
||||
|
||||
import { CreateBrainProps } from "@/lib/components/AddBrainModal/types/types";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
||||
export const useConnectableBrain = () => {
|
||||
const { setValue, getValues } = useFormContext<CreateBrainProps>();
|
||||
|
||||
const onCheckedChange = ({
|
||||
checked,
|
||||
brainId,
|
||||
}: {
|
||||
checked: CheckedState;
|
||||
brainId: UUID;
|
||||
}) => {
|
||||
if (checked === "indeterminate") {
|
||||
return;
|
||||
}
|
||||
const connected_brains_ids = getValues("connected_brains_ids") ?? [];
|
||||
if (checked) {
|
||||
setValue("connected_brains_ids", [...connected_brains_ids, brainId]);
|
||||
} else {
|
||||
setValue(
|
||||
"connected_brains_ids",
|
||||
connected_brains_ids.filter((id) => id !== brainId)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
onCheckedChange,
|
||||
};
|
||||
};
|
@ -1,24 +0,0 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import { useBrainContext } from "@/lib/context/BrainProvider/hooks/useBrainContext";
|
||||
|
||||
import { ConnectableBrain } from "./Components/ConnectableBrain/ConnectableBrain";
|
||||
|
||||
export const CompositeBrainConnections = (): JSX.Element => {
|
||||
const { allBrains } = useBrainContext();
|
||||
const sortedBrains = allBrains.sort((a, b) => a.name.localeCompare(b.name));
|
||||
const { t } = useTranslation("brain");
|
||||
|
||||
return (
|
||||
<div className="px-10">
|
||||
<p className="text-center mb-8 italic text-sm w-full">
|
||||
{t("composite_brain_composition_invitation")}
|
||||
</p>
|
||||
<div className="w-full flex flex-col gap-2">
|
||||
{sortedBrains.map((brain) => (
|
||||
<ConnectableBrain key={brain.id} brain={brain} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
@ -10,7 +10,7 @@
|
||||
padding: Spacings.$spacing05;
|
||||
border-radius: Radius.$big;
|
||||
cursor: pointer;
|
||||
border: 2px solid transparent;
|
||||
border: 1px solid Colors.$lightest-black;
|
||||
|
||||
&.disabled {
|
||||
pointer-events: none;
|
||||
@ -35,6 +35,7 @@
|
||||
&:hover,
|
||||
&.selected {
|
||||
border-color: Colors.$primary;
|
||||
background-color: Colors.$primary-lightest;
|
||||
|
||||
.name {
|
||||
color: Colors.$primary;
|
||||
|
@ -10,6 +10,8 @@
|
||||
padding-inline: Spacings.$spacing08;
|
||||
height: 100%;
|
||||
gap: Spacings.$spacing05;
|
||||
overflow-y: hidden;
|
||||
overflow-x: visible;
|
||||
|
||||
@media (max-width: ScreenSizes.$small) {
|
||||
padding-inline: 0;
|
||||
@ -19,13 +21,22 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: Spacings.$spacing05;
|
||||
padding-top: Spacings.$spacing03;
|
||||
overflow-y: scroll;
|
||||
overflow-x: visible;
|
||||
|
||||
.title {
|
||||
@include Typography.H2;
|
||||
}
|
||||
}
|
||||
|
||||
.button {
|
||||
.buttons_wrapper {
|
||||
align-self: flex-end;
|
||||
|
||||
&.two_buttons {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-self: normal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,37 @@
|
||||
import { useState } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
import { IntegrationBrains } from "@/lib/api/brain/types";
|
||||
import { useBrainApi } from "@/lib/api/brain/useBrainApi";
|
||||
import { BrainType } from "@/lib/components/AddBrainModal/types/types";
|
||||
import QuivrButton from "@/lib/components/ui/QuivrButton/QuivrButton";
|
||||
|
||||
import { BrainTypeSelection } from "./BrainTypeSelection/BrainTypeSelection";
|
||||
import styles from "./BrainTypeSelectionStep.module.scss";
|
||||
import { CustomBrainList } from "./CustomBrainList/CustomBrainList";
|
||||
|
||||
import { useBrainCreationContext } from "../../brainCreation-provider";
|
||||
import { useBrainCreationSteps } from "../../hooks/useBrainCreationSteps";
|
||||
|
||||
export const BrainTypeSelectionStep = (): JSX.Element => {
|
||||
const [selectedIndex, setSelectedIndex] = useState<number>(0);
|
||||
const [customBrainsCatalogueOpened, setCustomBrainsCatalogueOpened] =
|
||||
useState<boolean>(false);
|
||||
const [customBrains, setCustomBrains] = useState<IntegrationBrains[]>([]);
|
||||
const { goToNextStep, currentStepIndex } = useBrainCreationSteps();
|
||||
const { getIntegrationBrains } = useBrainApi();
|
||||
const { currentIntegrationBrain } = useBrainCreationContext();
|
||||
|
||||
useEffect(() => {
|
||||
getIntegrationBrains()
|
||||
.then((response) => {
|
||||
setCustomBrains(
|
||||
response.filter((brain) => brain.integration_type === "custom")
|
||||
);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
});
|
||||
}, []);
|
||||
|
||||
const brainTypes: BrainType[] = [
|
||||
{
|
||||
@ -18,6 +39,15 @@ export const BrainTypeSelectionStep = (): JSX.Element => {
|
||||
description: "Upload documents or website links to feed your brain.",
|
||||
iconName: "feed",
|
||||
},
|
||||
{
|
||||
name: "Custom Brain",
|
||||
description:
|
||||
"Explore your databases, converse with your APIs, and much more!",
|
||||
iconName: "custom",
|
||||
onClick: () => {
|
||||
setCustomBrainsCatalogueOpened(true);
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Sync Brain - Coming soon!",
|
||||
description:
|
||||
@ -25,13 +55,6 @@ export const BrainTypeSelectionStep = (): JSX.Element => {
|
||||
iconName: "software",
|
||||
disabled: true,
|
||||
},
|
||||
{
|
||||
name: "Custom Brain - Coming soon!",
|
||||
description:
|
||||
"Explore your databases, converse with your APIs, and much more!",
|
||||
iconName: "custom",
|
||||
disabled: true,
|
||||
},
|
||||
];
|
||||
|
||||
const next = (): void => {
|
||||
@ -45,23 +68,53 @@ export const BrainTypeSelectionStep = (): JSX.Element => {
|
||||
return (
|
||||
<div className={styles.brain_types_wrapper}>
|
||||
<div className={styles.main_wrapper}>
|
||||
{customBrainsCatalogueOpened ? (
|
||||
<CustomBrainList customBrainList={customBrains} />
|
||||
) : (
|
||||
<>
|
||||
<span className={styles.title}>Choose a type of brain</span>
|
||||
{brainTypes.map((brainType, index) => (
|
||||
<div key={index}>
|
||||
<BrainTypeSelection
|
||||
brainType={brainType}
|
||||
selected={index === selectedIndex}
|
||||
onClick={() => setSelectedIndex(index)}
|
||||
onClick={() => {
|
||||
setSelectedIndex(index);
|
||||
if (brainType.onClick) {
|
||||
brainType.onClick();
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<div className={styles.button}>
|
||||
<div
|
||||
className={`${styles.buttons_wrapper} ${
|
||||
customBrainsCatalogueOpened ? styles.two_buttons : ""
|
||||
}`}
|
||||
>
|
||||
{customBrainsCatalogueOpened && (
|
||||
<QuivrButton
|
||||
label="Type of brain"
|
||||
iconName="chevronLeft"
|
||||
color="primary"
|
||||
onClick={() => {
|
||||
setCustomBrainsCatalogueOpened(false);
|
||||
setSelectedIndex(-1);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<QuivrButton
|
||||
label="Next Step"
|
||||
iconName="chevronRight"
|
||||
color="primary"
|
||||
onClick={() => next()}
|
||||
disabled={
|
||||
selectedIndex === -1 ||
|
||||
(!!customBrainsCatalogueOpened && !currentIntegrationBrain)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -0,0 +1,44 @@
|
||||
@use "@/styles/Colors.module.scss";
|
||||
@use "@/styles/Radius.module.scss";
|
||||
@use "@/styles/ScreenSizes.module.scss";
|
||||
@use "@/styles/Spacings.module.scss";
|
||||
@use "@/styles/Typography.module.scss";
|
||||
|
||||
.cards_wrapper {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: Spacings.$spacing05;
|
||||
|
||||
.title {
|
||||
@include Typography.H2;
|
||||
}
|
||||
|
||||
.brain_card_wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
border-radius: Radius.$normal;
|
||||
gap: Spacings.$spacing03;
|
||||
padding: Spacings.$spacing04;
|
||||
border: 1px solid Colors.$lightest-black;
|
||||
width: fit-content;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
|
||||
.brain_title {
|
||||
font-size: Typography.$small;
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&.selected {
|
||||
border-color: Colors.$primary;
|
||||
background-color: Colors.$primary-lightest;
|
||||
|
||||
.brain_title {
|
||||
color: Colors.$primary;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
import Image from "next/image";
|
||||
|
||||
import { IntegrationBrains } from "@/lib/api/brain/types";
|
||||
import { MessageInfoBox } from "@/lib/components/ui/MessageInfoBox/MessageInfoBox";
|
||||
import Tooltip from "@/lib/components/ui/Tooltip/Tooltip";
|
||||
|
||||
import styles from "./CustomBrainList.module.scss";
|
||||
|
||||
import { useBrainCreationContext } from "../../../brainCreation-provider";
|
||||
|
||||
export const CustomBrainList = ({
|
||||
customBrainList,
|
||||
}: {
|
||||
customBrainList: IntegrationBrains[];
|
||||
}): JSX.Element => {
|
||||
const { setCurrentIntegrationBrain, currentIntegrationBrain } =
|
||||
useBrainCreationContext();
|
||||
|
||||
return (
|
||||
<div className={styles.cards_wrapper}>
|
||||
<MessageInfoBox content="More custom brains are coming!" type="info" />
|
||||
<span className={styles.title}>Choose a custom brain</span>
|
||||
<div>
|
||||
{customBrainList.map((brain) => {
|
||||
return (
|
||||
<div
|
||||
key={brain.id}
|
||||
onClick={() => setCurrentIntegrationBrain(brain)}
|
||||
>
|
||||
<Tooltip tooltip={brain.description}>
|
||||
<div
|
||||
className={`${styles.brain_card_wrapper} ${
|
||||
currentIntegrationBrain === brain ? styles.selected : ""
|
||||
}`}
|
||||
>
|
||||
<Image
|
||||
src={brain.integration_logo_url}
|
||||
alt={brain.integration_name}
|
||||
width={50}
|
||||
height={50}
|
||||
/>
|
||||
<span className={styles.brain_title}>
|
||||
{brain.integration_name}
|
||||
</span>
|
||||
</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
@ -1,16 +1,18 @@
|
||||
import { KnowledgeToFeed } from "@/app/chat/[chatId]/components/ActionsBar/components";
|
||||
import { MessageInfoBox } from "@/lib/components/ui/MessageInfoBox/MessageInfoBox";
|
||||
import QuivrButton from "@/lib/components/ui/QuivrButton/QuivrButton";
|
||||
|
||||
import styles from "./BrainKnowledgeStep.module.scss";
|
||||
import styles from "./CreateBrainStep.module.scss";
|
||||
import { useBrainCreationApi } from "./hooks/useBrainCreationApi";
|
||||
|
||||
import { useBrainCreationContext } from "../../brainCreation-provider";
|
||||
import { useBrainCreationSteps } from "../../hooks/useBrainCreationSteps";
|
||||
|
||||
export const BrainKnowledgeStep = (): JSX.Element => {
|
||||
export const CreateBrainStep = (): JSX.Element => {
|
||||
const { currentStepIndex, goToPreviousStep } = useBrainCreationSteps();
|
||||
const { createBrain } = useBrainCreationApi();
|
||||
const { creating, setCreating } = useBrainCreationContext();
|
||||
const { creating, setCreating, currentIntegrationBrain } =
|
||||
useBrainCreationContext();
|
||||
|
||||
const previous = (): void => {
|
||||
goToPreviousStep();
|
||||
@ -27,10 +29,17 @@ export const BrainKnowledgeStep = (): JSX.Element => {
|
||||
|
||||
return (
|
||||
<div className={styles.brain_knowledge_wrapper}>
|
||||
{!currentIntegrationBrain ? (
|
||||
<div>
|
||||
<span className={styles.title}>Feed your brain</span>
|
||||
<KnowledgeToFeed hideBrainSelector={true} />
|
||||
</div>
|
||||
) : (
|
||||
<MessageInfoBox
|
||||
content="Your custom brain is ready to be created"
|
||||
type="success"
|
||||
/>
|
||||
)}
|
||||
<div className={styles.buttons_wrapper}>
|
||||
<QuivrButton
|
||||
label="Previous step"
|
@ -4,6 +4,7 @@ import { useFormContext } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import { PUBLIC_BRAINS_KEY } from "@/lib/api/brain/config";
|
||||
import { IntegrationSettings } from "@/lib/api/brain/types";
|
||||
import { CreateBrainProps } from "@/lib/components/AddBrainModal/types/types";
|
||||
import { useKnowledgeToFeedInput } from "@/lib/components/KnowledgeToFeedInput/hooks/useKnowledgeToFeedInput.ts";
|
||||
import { useBrainContext } from "@/lib/context/BrainProvider/hooks/useBrainContext";
|
||||
@ -23,8 +24,11 @@ export const useBrainCreationApi = () => {
|
||||
const { setKnowledgeToFeed } = useKnowledgeToFeedContext();
|
||||
const { createBrain: createBrainApi, setCurrentBrainId } = useBrainContext();
|
||||
const { crawlWebsiteHandler, uploadFileHandler } = useKnowledgeToFeedInput();
|
||||
const { setIsBrainCreationModalOpened, setCreating } =
|
||||
useBrainCreationContext();
|
||||
const {
|
||||
setIsBrainCreationModalOpened,
|
||||
setCreating,
|
||||
currentIntegrationBrain,
|
||||
} = useBrainCreationContext();
|
||||
|
||||
const handleFeedBrain = async (brainId: UUID): Promise<void> => {
|
||||
const uploadPromises = files.map((file) =>
|
||||
@ -37,26 +41,21 @@ export const useBrainCreationApi = () => {
|
||||
};
|
||||
|
||||
const createBrain = async (): Promise<void> => {
|
||||
const {
|
||||
name,
|
||||
description,
|
||||
brain_definition,
|
||||
brain_secrets_values,
|
||||
status,
|
||||
brain_type,
|
||||
connected_brains_ids,
|
||||
} = getValues();
|
||||
const { name, description } = getValues();
|
||||
let integrationSettings: IntegrationSettings | undefined = undefined;
|
||||
|
||||
if (currentIntegrationBrain) {
|
||||
integrationSettings = {
|
||||
integration_id: currentIntegrationBrain.id,
|
||||
settings: {},
|
||||
};
|
||||
}
|
||||
|
||||
const createdBrainId = await createBrainApi({
|
||||
brain_type: currentIntegrationBrain ? "integration" : "doc",
|
||||
name,
|
||||
description,
|
||||
status,
|
||||
brain_type,
|
||||
brain_definition: brain_type === "api" ? brain_definition : undefined,
|
||||
brain_secrets_values:
|
||||
brain_type === "api" ? brain_secrets_values : undefined,
|
||||
connected_brains_ids:
|
||||
brain_type === "composite" ? connected_brains_ids : undefined,
|
||||
integration: integrationSettings,
|
||||
});
|
||||
|
||||
if (createdBrainId === undefined) {
|
||||
@ -67,9 +66,8 @@ export const useBrainCreationApi = () => {
|
||||
|
||||
return;
|
||||
}
|
||||
if (brain_type === "doc") {
|
||||
|
||||
void handleFeedBrain(createdBrainId);
|
||||
}
|
||||
|
||||
setCurrentBrainId(createdBrainId);
|
||||
setIsBrainCreationModalOpened(false);
|
@ -1,3 +1,5 @@
|
||||
import Image from "next/image";
|
||||
|
||||
import { useBrainContext } from "@/lib/context/BrainProvider/hooks/useBrainContext";
|
||||
|
||||
import styles from "./CurrentBrain.module.scss";
|
||||
@ -27,7 +29,16 @@ export const CurrentBrain = ({
|
||||
<div className={styles.left}>
|
||||
<span>Talking to</span>
|
||||
<div className={styles.brain_name_wrapper}>
|
||||
{currentBrain.integration_logo_url ? (
|
||||
<Image
|
||||
src={currentBrain.integration_logo_url}
|
||||
alt="brain"
|
||||
width={18}
|
||||
height={18}
|
||||
/>
|
||||
) : (
|
||||
<Icon size="small" name="brain" color="primary" />
|
||||
)}
|
||||
<span className={styles.brain_name}>{currentBrain.name}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,4 +1,4 @@
|
||||
import Tooltip from "@/lib/components/ui/Tooltip";
|
||||
import Tooltip from "@/lib/components/ui/Tooltip/Tooltip";
|
||||
|
||||
import { enhanceUrlDisplay } from "./utils/enhanceUrlDisplay";
|
||||
import { removeFileExtension } from "./utils/removeFileExtension";
|
||||
|
@ -33,6 +33,7 @@ export const PageHeader = ({
|
||||
onClick={button.onClick}
|
||||
color={button.color}
|
||||
iconName={button.iconName}
|
||||
hidden={button.hidden}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
@ -4,7 +4,7 @@ import { HTMLAttributes } from "react";
|
||||
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
import Tooltip from "./Tooltip";
|
||||
import Tooltip from "./Tooltip/Tooltip";
|
||||
|
||||
interface EllipsisProps extends HTMLAttributes<HTMLDivElement> {
|
||||
children: string;
|
||||
|
@ -69,6 +69,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
.success {
|
||||
color: Colors.$success;
|
||||
}
|
||||
|
||||
.disabled {
|
||||
color: Colors.$black;
|
||||
pointer-events: none;
|
||||
|
@ -0,0 +1,18 @@
|
||||
@use "@/styles/Colors.module.scss";
|
||||
@use "@/styles/Radius.module.scss";
|
||||
@use "@/styles/Spacings.module.scss";
|
||||
|
||||
.message_info_box_wrapper {
|
||||
padding: Spacings.$spacing03;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: Spacings.$spacing03;
|
||||
width: 100%;
|
||||
border: 1px solid Colors.$normal-grey;
|
||||
color: Colors.$black;
|
||||
border-radius: Radius.$normal;
|
||||
|
||||
&.success {
|
||||
border-color: Colors.$success;
|
||||
}
|
||||
}
|
41
frontend/lib/components/ui/MessageInfoBox/MessageInfoBox.tsx
Normal file
41
frontend/lib/components/ui/MessageInfoBox/MessageInfoBox.tsx
Normal file
@ -0,0 +1,41 @@
|
||||
import { iconList } from "@/lib/helpers/iconList";
|
||||
import { Color } from "@/lib/types/Colors";
|
||||
|
||||
import styles from "./MessageInfoBox.module.scss";
|
||||
|
||||
import { Icon } from "../Icon/Icon";
|
||||
|
||||
export type MessageInfoBoxProps = {
|
||||
content: string;
|
||||
type: "info" | "success" | "warning" | "error";
|
||||
};
|
||||
|
||||
export const MessageInfoBox = ({
|
||||
content,
|
||||
type,
|
||||
}: MessageInfoBoxProps): JSX.Element => {
|
||||
const getIconProps = (): {
|
||||
iconName: keyof typeof iconList;
|
||||
iconColor: Color;
|
||||
} => {
|
||||
switch (type) {
|
||||
case "info":
|
||||
return { iconName: "info", iconColor: "grey" };
|
||||
case "success":
|
||||
return { iconName: "check", iconColor: "success" };
|
||||
default:
|
||||
return { iconName: "info", iconColor: "grey" };
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={`${styles.message_info_box_wrapper} ${styles[type]} `}>
|
||||
<Icon
|
||||
name={getIconProps().iconName}
|
||||
size="normal"
|
||||
color={getIconProps().iconColor}
|
||||
/>
|
||||
<span>{content}</span>
|
||||
</div>
|
||||
);
|
||||
};
|
@ -15,6 +15,10 @@
|
||||
display: flex;
|
||||
width: fit-content;
|
||||
|
||||
&.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&.primary {
|
||||
border-color: Colors.$primary;
|
||||
color: Colors.$primary;
|
||||
|
@ -14,6 +14,7 @@ export const QuivrButton = ({
|
||||
isLoading,
|
||||
iconName,
|
||||
disabled,
|
||||
hidden,
|
||||
}: ButtonType): JSX.Element => {
|
||||
const [hovered, setHovered] = useState<boolean>(false);
|
||||
|
||||
@ -23,6 +24,7 @@ export const QuivrButton = ({
|
||||
${styles.button_wrapper}
|
||||
${styles[color]}
|
||||
${disabled ? styles.disabled : ""}
|
||||
${hidden ? styles.hidden : ""}
|
||||
`}
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||
onClick={() => onClick()}
|
||||
|
13
frontend/lib/components/ui/Tooltip/Tooltip.module.scss
Normal file
13
frontend/lib/components/ui/Tooltip/Tooltip.module.scss
Normal file
@ -0,0 +1,13 @@
|
||||
@use "@/styles/Colors.module.scss";
|
||||
@use "@/styles/Radius.module.scss";
|
||||
@use "@/styles/Spacings.module.scss";
|
||||
@use "@/styles/Typography.module.scss";
|
||||
@use "@/styles/ZIndexes.module.scss";
|
||||
|
||||
.tooltip_content_wrapper {
|
||||
z-index: ZIndexes.$tooltip;
|
||||
background-color: Colors.$lightest-black;
|
||||
padding: Spacings.$spacing03;
|
||||
border-radius: Radius.$normal;
|
||||
font-size: Typography.$small;
|
||||
}
|
@ -3,6 +3,8 @@ import * as TooltipPrimitive from "@radix-ui/react-tooltip";
|
||||
import { AnimatePresence, motion } from "framer-motion";
|
||||
import { ReactNode, useState } from "react";
|
||||
|
||||
import styles from "./Tooltip.module.scss";
|
||||
|
||||
interface TooltipProps {
|
||||
children?: ReactNode;
|
||||
tooltip?: ReactNode;
|
||||
@ -31,11 +33,9 @@ const Tooltip = ({ children, tooltip }: TooltipProps): JSX.Element => {
|
||||
opacity: 0,
|
||||
transition: { ease: "easeIn", duration: 0.1 },
|
||||
}}
|
||||
// transition={{ duration: 0.2, ease: "circInOut" }}
|
||||
className="select-none rounded-md border border-black/10 dark:border-white/25 bg-white dark:bg-gray-800 px-5 py-3 text-sm leading-none shadow-lg dark:shadow-primary/25"
|
||||
className={styles.tooltip_content_wrapper}
|
||||
>
|
||||
{tooltip}
|
||||
<TooltipPrimitive.Arrow className="fill-white dark:fill-black" />
|
||||
</motion.div>
|
||||
</TooltipPrimitive.Content>
|
||||
</TooltipPrimitive.Portal>
|
@ -26,6 +26,7 @@ export const addBrainDefaultValues: CreateBrainInput = {
|
||||
jq_instructions: "",
|
||||
},
|
||||
connected_brains_ids: [],
|
||||
integration: undefined,
|
||||
};
|
||||
|
||||
export const defaultModel: Model = "gpt-3.5-turbo";
|
||||
|
@ -10,6 +10,16 @@ import { BrainType, Model } from "../../types/BrainConfig";
|
||||
|
||||
export type BrainAccessStatus = "private" | "public";
|
||||
|
||||
export type IntegrationDescription = {
|
||||
connection_settings?: object;
|
||||
description: string;
|
||||
id: UUID;
|
||||
integration_logo_url: string;
|
||||
integration_name: string;
|
||||
integration_type: "custom" | "sync";
|
||||
max_files: number;
|
||||
};
|
||||
|
||||
export type Brain = {
|
||||
id: UUID;
|
||||
name: string;
|
||||
@ -22,6 +32,7 @@ export type Brain = {
|
||||
prompt_id?: string | null;
|
||||
brain_type?: BrainType;
|
||||
brain_definition?: ApiBrainDefinition;
|
||||
integration_description?: IntegrationDescription;
|
||||
};
|
||||
|
||||
export type MinimalBrainForUser = {
|
||||
@ -31,6 +42,8 @@ export type MinimalBrainForUser = {
|
||||
status: BrainAccessStatus;
|
||||
brain_type: BrainType;
|
||||
description: string;
|
||||
integration_logo_url?: string;
|
||||
max_files: number;
|
||||
};
|
||||
|
||||
//TODO: rename rights to role in Backend and use MinimalBrainForUser instead of BackendMinimalBrainForUser
|
||||
@ -44,7 +57,7 @@ export type PublicBrain = {
|
||||
description?: string;
|
||||
number_of_subscribers: number;
|
||||
last_update: string;
|
||||
brain_type: BrainType;
|
||||
brain_type?: BrainType;
|
||||
brain_definition?: ApiBrainDefinition;
|
||||
};
|
||||
|
||||
|
@ -10,8 +10,14 @@ import {
|
||||
FaRegUserCircle,
|
||||
FaUnlock,
|
||||
} from "react-icons/fa";
|
||||
import { FaInfo } from "react-icons/fa6";
|
||||
import { FiUpload } from "react-icons/fi";
|
||||
import { IoIosAdd, IoMdClose, IoMdLogOut } from "react-icons/io";
|
||||
import {
|
||||
IoIosAdd,
|
||||
IoIosHelpCircleOutline,
|
||||
IoMdClose,
|
||||
IoMdLogOut,
|
||||
} from "react-icons/io";
|
||||
import {
|
||||
IoArrowUpCircleOutline,
|
||||
IoHomeOutline,
|
||||
@ -66,8 +72,10 @@ export const iconList: { [name: string]: IconType } = {
|
||||
followUp: IoArrowUpCircleOutline,
|
||||
graph: VscGraph,
|
||||
hastag: RiHashtag,
|
||||
help: IoIosHelpCircleOutline,
|
||||
history: MdHistory,
|
||||
home: IoHomeOutline,
|
||||
info: FaInfo,
|
||||
key: FaKey,
|
||||
loader: AiOutlineLoading3Quarters,
|
||||
logout: IoMdLogOut,
|
||||
|
@ -4,12 +4,12 @@ import { ApiBrainDefinition } from "../api/brain/types";
|
||||
|
||||
export const brainStatuses = ["private", "public"] as const;
|
||||
|
||||
export type BrainStatus = (typeof brainStatuses)[number];
|
||||
|
||||
export const brainTypes = ["doc", "api", "composite"] as const;
|
||||
export const brainTypes = ["doc", "api", "composite", "integration"] as const;
|
||||
|
||||
export type BrainType = (typeof brainTypes)[number];
|
||||
|
||||
export type BrainStatus = (typeof brainStatuses)[number];
|
||||
|
||||
export type Model = (typeof freeModels)[number];
|
||||
|
||||
// TODO: update this type to match the backend (antropic, openai and some other keys should be removed)
|
||||
|
@ -6,4 +6,5 @@ export type Color =
|
||||
| "gold"
|
||||
| "accent"
|
||||
| "white"
|
||||
| "dangerous";
|
||||
| "dangerous"
|
||||
| "success";
|
||||
|
@ -9,4 +9,5 @@ export interface ButtonType {
|
||||
iconName: keyof typeof iconList;
|
||||
onClick: () => void | Promise<void>;
|
||||
disabled?: boolean;
|
||||
hidden?: boolean;
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
$base: 1000;
|
||||
$overlay: 1010;
|
||||
$modal: 1020;
|
||||
$tooltip: 1030;
|
||||
|
Loading…
Reference in New Issue
Block a user