+ {brains.map((brain) => {
return (
setCurrentIntegrationBrain(brain)}
+ className={styles.brain_card_container}
+ onClick={() => {
+ next();
+ setCurrentSelectedBrain(brain);
+ }}
>
{brain.integration_name}
+
+ {brain.tags[0] && (
+
+ )}
+
diff --git a/frontend/lib/components/AddBrainModal/components/BrainTypeSelectionStep/BrainTypeSelection/BrainTypeSelection.module.scss b/frontend/lib/components/AddBrainModal/components/BrainTypeSelectionStep/BrainTypeSelection/BrainTypeSelection.module.scss
deleted file mode 100644
index 35b16ed5d..000000000
--- a/frontend/lib/components/AddBrainModal/components/BrainTypeSelectionStep/BrainTypeSelection/BrainTypeSelection.module.scss
+++ /dev/null
@@ -1,48 +0,0 @@
-@use "@/styles/Colors.module.scss";
-@use "@/styles/Radius.module.scss";
-@use "@/styles/Spacings.module.scss";
-@use "@/styles/Typography.module.scss";
-
-.brain_type_wrapper {
- display: flex;
- flex-direction: column;
- gap: Spacings.$spacing05;
- padding: Spacings.$spacing05;
- border-radius: Radius.$big;
- cursor: pointer;
- border: 1px solid Colors.$lightest-black;
-
- &.disabled {
- pointer-events: none;
- background-color: Colors.$lightest-grey;
- opacity: 0.6;
- }
-
- .first_line_wrapper {
- display: flex;
- gap: Spacings.$spacing03;
- align-items: center;
-
- .name {
- @include Typography.H3;
- }
- }
-
- .description {
- color: Colors.$dark-grey;
- }
-
- &:hover,
- &.selected {
- border-color: Colors.$primary;
- background-color: Colors.$primary-lightest;
-
- .name {
- color: Colors.$primary;
- }
-
- .description {
- color: Colors.$black;
- }
- }
-}
diff --git a/frontend/lib/components/AddBrainModal/components/BrainTypeSelectionStep/BrainTypeSelection/BrainTypeSelection.tsx b/frontend/lib/components/AddBrainModal/components/BrainTypeSelectionStep/BrainTypeSelection/BrainTypeSelection.tsx
deleted file mode 100644
index 2a85d8dfa..000000000
--- a/frontend/lib/components/AddBrainModal/components/BrainTypeSelectionStep/BrainTypeSelection/BrainTypeSelection.tsx
+++ /dev/null
@@ -1,41 +0,0 @@
-import { useState } from "react";
-
-import { BrainType } from "@/lib/components/AddBrainModal/types/types";
-import Icon from "@/lib/components/ui/Icon/Icon";
-
-import styles from "./BrainTypeSelection.module.scss";
-
-export const BrainTypeSelection = ({
- brainType,
- onClick,
- selected,
-}: {
- brainType: BrainType;
- onClick: () => void;
- selected: boolean;
-}): JSX.Element => {
- const [isHovered, setIsHovered] = useState
(false);
-
- return (
- setIsHovered(true)}
- onMouseLeave={() => setIsHovered(false)}
- onClick={onClick}
- >
-
-
- {brainType.name}
-
-
{brainType.description}
-
- );
-};
diff --git a/frontend/lib/components/AddBrainModal/components/BrainTypeSelectionStep/BrainTypeSelectionStep.tsx b/frontend/lib/components/AddBrainModal/components/BrainTypeSelectionStep/BrainTypeSelectionStep.tsx
index cf2caee92..184149376 100644
--- a/frontend/lib/components/AddBrainModal/components/BrainTypeSelectionStep/BrainTypeSelectionStep.tsx
+++ b/frontend/lib/components/AddBrainModal/components/BrainTypeSelectionStep/BrainTypeSelectionStep.tsx
@@ -1,66 +1,34 @@
import { useEffect, useState } from "react";
+import { useFormContext } from "react-hook-form";
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 { BrainCatalogue } from "./BrainCatalogue/BrainCatalogue";
import styles from "./BrainTypeSelectionStep.module.scss";
-import { CustomBrainList } from "./CustomBrainList/CustomBrainList";
-import { useBrainCreationContext } from "../../brainCreation-provider";
import { useBrainCreationSteps } from "../../hooks/useBrainCreationSteps";
+import { CreateBrainProps } from "../../types/types";
export const BrainTypeSelectionStep = (): JSX.Element => {
- const [selectedIndex, setSelectedIndex] = useState(-1);
- const [customBrainsCatalogueOpened, setCustomBrainsCatalogueOpened] =
- useState(false);
- const [customBrains, setCustomBrains] = useState([]);
+ const [brains, setBrains] = useState([]);
const { goToNextStep, currentStepIndex } = useBrainCreationSteps();
const { getIntegrationBrains } = useBrainApi();
- const { currentIntegrationBrain } = useBrainCreationContext();
+ const { setValue } = useFormContext();
useEffect(() => {
getIntegrationBrains()
.then((response) => {
- setCustomBrains(
- response.filter((brain) => brain.integration_type === "custom")
- );
+ setBrains(response);
})
.catch((error) => {
console.error(error);
});
+
+ setValue("name", "");
+ setValue("description", "");
}, []);
- const brainTypes: BrainType[] = [
- {
- name: "Core Brain",
- 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:
- "Connect to your tools and applications to interact with your data.",
- iconName: "software",
- disabled: true,
- },
- ];
-
- const next = (): void => {
- goToNextStep();
- };
-
if (currentStepIndex !== 0) {
return <>>;
}
@@ -68,54 +36,7 @@ export const BrainTypeSelectionStep = (): JSX.Element => {
return (
- {customBrainsCatalogueOpened ? (
-
- ) : (
- <>
-
Choose a type of brain
- {brainTypes.map((brainType, index) => (
-
- {
- setSelectedIndex(index);
- if (brainType.onClick) {
- brainType.onClick();
- }
- }}
- />
-
- ))}
- >
- )}
-
-
- {customBrainsCatalogueOpened && (
- {
- setCustomBrainsCatalogueOpened(false);
- setSelectedIndex(-1);
- }}
- />
- )}
- next()}
- disabled={
- selectedIndex === -1 ||
- (!!customBrainsCatalogueOpened && !currentIntegrationBrain)
- }
- />
+
);
diff --git a/frontend/lib/components/AddBrainModal/components/BrainTypeSelectionStep/CustomBrainList/CustomBrainList.module.scss b/frontend/lib/components/AddBrainModal/components/BrainTypeSelectionStep/CustomBrainList/CustomBrainList.module.scss
deleted file mode 100644
index e5b697d43..000000000
--- a/frontend/lib/components/AddBrainModal/components/BrainTypeSelectionStep/CustomBrainList/CustomBrainList.module.scss
+++ /dev/null
@@ -1,44 +0,0 @@
-@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;
- }
- }
- }
-}
diff --git a/frontend/lib/components/AddBrainModal/components/CreateBrainStep/CreateBrainStep.module.scss b/frontend/lib/components/AddBrainModal/components/CreateBrainStep/CreateBrainStep.module.scss
index 27814da17..fdfc3ebe4 100644
--- a/frontend/lib/components/AddBrainModal/components/CreateBrainStep/CreateBrainStep.module.scss
+++ b/frontend/lib/components/AddBrainModal/components/CreateBrainStep/CreateBrainStep.module.scss
@@ -12,6 +12,12 @@
@include Typography.H2;
}
+ .settings_wrapper {
+ display: flex;
+ flex-direction: column;
+ gap: Spacings.$spacing05;
+ }
+
.message_info_box_wrapper {
align-self: center;
display: flex;
diff --git a/frontend/lib/components/AddBrainModal/components/CreateBrainStep/CreateBrainStep.tsx b/frontend/lib/components/AddBrainModal/components/CreateBrainStep/CreateBrainStep.tsx
index a387d8730..ca3c1c9a3 100644
--- a/frontend/lib/components/AddBrainModal/components/CreateBrainStep/CreateBrainStep.tsx
+++ b/frontend/lib/components/AddBrainModal/components/CreateBrainStep/CreateBrainStep.tsx
@@ -1,6 +1,10 @@
+import { capitalCase } from "change-case";
+import { useEffect, useState } from "react";
+
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 { TextInput } from "@/lib/components/ui/TextInput/TextInput";
import styles from "./CreateBrainStep.module.scss";
import { useBrainCreationApi } from "./hooks/useBrainCreationApi";
@@ -10,9 +14,29 @@ import { useBrainCreationSteps } from "../../hooks/useBrainCreationSteps";
export const CreateBrainStep = (): JSX.Element => {
const { currentStepIndex, goToPreviousStep } = useBrainCreationSteps();
- const { createBrain } = useBrainCreationApi();
- const { creating, setCreating, currentIntegrationBrain } =
+ const { createBrain, fields, setFields } = useBrainCreationApi();
+ const { creating, setCreating, currentSelectedBrain } =
useBrainCreationContext();
+ const [createBrainStepIndex, setCreateBrainStepIndex] = useState(0);
+
+ useEffect(() => {
+ if (currentSelectedBrain?.connection_settings) {
+ const newFields = Object.entries(
+ currentSelectedBrain.connection_settings
+ ).map(([key, type]) => {
+ return { name: key, type, value: "" };
+ });
+ setFields(newFields);
+ }
+
+ setCreateBrainStepIndex(Number(!currentSelectedBrain?.connection_settings));
+ }, [currentSelectedBrain?.connection_settings]);
+
+ const handleInputChange = (name: string, value: string) => {
+ setFields(
+ fields.map((field) => (field.name === name ? { ...field, value } : field))
+ );
+ };
const previous = (): void => {
goToPreviousStep();
@@ -29,28 +53,48 @@ export const CreateBrainStep = (): JSX.Element => {
return (
- {!currentIntegrationBrain ? (
+ {!createBrainStepIndex && (
+
+
+ {currentSelectedBrain?.information}
+
+ {fields.map(({ name, value }) => (
+
+ handleInputChange(name, inputValue)
+ }
+ label={capitalCase(name)}
+ />
+ ))}
+
+ )}
+ {!!currentSelectedBrain?.max_files && !!createBrainStepIndex && (
Feed your brain
- ) : (
-
-
-
- Click on
-
- to finish your brain creation.
-
-
-
)}
+ {!currentSelectedBrain?.max_files &&
+ !currentSelectedBrain?.connection_settings && (
+
+
+
+ Click on
+
+ to finish your brain creation.
+
+
+
+ )}
+
{
iconName="chevronLeft"
onClick={previous}
/>
-
+ {(!currentSelectedBrain?.max_files && !createBrainStepIndex) ||
+ createBrainStepIndex ? (
+
+ ) : (
+ setCreateBrainStepIndex(1)}
+ isLoading={creating}
+ />
+ )}
);
diff --git a/frontend/lib/components/AddBrainModal/components/CreateBrainStep/hooks/useBrainCreationApi.ts b/frontend/lib/components/AddBrainModal/components/CreateBrainStep/hooks/useBrainCreationApi.ts
index e21e75e17..fb80a4c1c 100644
--- a/frontend/lib/components/AddBrainModal/components/CreateBrainStep/hooks/useBrainCreationApi.ts
+++ b/frontend/lib/components/AddBrainModal/components/CreateBrainStep/hooks/useBrainCreationApi.ts
@@ -1,5 +1,6 @@
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { UUID } from "crypto";
+import { useState } from "react";
import { useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next";
@@ -24,11 +25,11 @@ export const useBrainCreationApi = () => {
const { setKnowledgeToFeed } = useKnowledgeToFeedContext();
const { createBrain: createBrainApi, setCurrentBrainId } = useBrainContext();
const { crawlWebsiteHandler, uploadFileHandler } = useKnowledgeToFeedInput();
- const {
- setIsBrainCreationModalOpened,
- setCreating,
- currentIntegrationBrain,
- } = useBrainCreationContext();
+ const { setIsBrainCreationModalOpened, setCreating, currentSelectedBrain } =
+ useBrainCreationContext();
+ const [fields, setFields] = useState<
+ { name: string; type: string; value: string }[]
+ >([]);
const handleFeedBrain = async (brainId: UUID): Promise => {
const uploadPromises = files.map((file) =>
@@ -44,15 +45,19 @@ export const useBrainCreationApi = () => {
const { name, description } = getValues();
let integrationSettings: IntegrationSettings | undefined = undefined;
- if (currentIntegrationBrain) {
+ if (currentSelectedBrain) {
integrationSettings = {
- integration_id: currentIntegrationBrain.id,
- settings: {},
+ integration_id: currentSelectedBrain.id,
+ settings: fields.reduce((acc, field) => {
+ acc[field.name] = field.value;
+
+ return acc;
+ }, {} as { [key: string]: string }),
};
}
const createdBrainId = await createBrainApi({
- brain_type: currentIntegrationBrain ? "integration" : "doc",
+ brain_type: currentSelectedBrain ? "integration" : "doc",
name,
description,
integration: integrationSettings,
@@ -98,5 +103,7 @@ export const useBrainCreationApi = () => {
return {
createBrain: mutate,
isBrainCreationPending,
+ fields,
+ setFields,
};
};
diff --git a/frontend/lib/components/AddBrainModal/hooks/useBrainCreationSteps.ts b/frontend/lib/components/AddBrainModal/hooks/useBrainCreationSteps.ts
index a2b179b01..ee0b145d4 100644
--- a/frontend/lib/components/AddBrainModal/hooks/useBrainCreationSteps.ts
+++ b/frontend/lib/components/AddBrainModal/hooks/useBrainCreationSteps.ts
@@ -1,3 +1,4 @@
+import { useEffect } from "react";
import { useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next";
@@ -6,9 +7,12 @@ import {
Step,
} from "@/lib/components/AddBrainModal/types/types";
+import { useBrainCreationContext } from "../brainCreation-provider";
+
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export const useBrainCreationSteps = () => {
const { t } = useTranslation("brain");
+ const { isBrainCreationModalOpened } = useBrainCreationContext();
const steps: Step[] = [
{
@@ -30,6 +34,10 @@ export const useBrainCreationSteps = () => {
(step) => step.value === currentStep
);
+ useEffect(() => {
+ goToFirstStep();
+ }, [isBrainCreationModalOpened]);
+
const goToNextStep = () => {
if (currentStepIndex === -1 || currentStepIndex === steps.length - 1) {
return;
@@ -48,6 +56,10 @@ export const useBrainCreationSteps = () => {
return setValue("brainCreationStep", previousStep.value);
};
+ const goToFirstStep = () => {
+ return setValue("brainCreationStep", steps[0].value);
+ };
+
return {
currentStep,
steps,
diff --git a/frontend/lib/components/ui/Tag/Tag.module.scss b/frontend/lib/components/ui/Tag/Tag.module.scss
new file mode 100644
index 000000000..052eeb9dc
--- /dev/null
+++ b/frontend/lib/components/ui/Tag/Tag.module.scss
@@ -0,0 +1,20 @@
+@use "@/styles/Colors.module.scss";
+@use "@/styles/Radius.module.scss";
+@use "@/styles/Spacings.module.scss";
+@use "@/styles/Typography.module.scss";
+
+.tag_wrapper {
+ padding: Spacings.$spacing01;
+ padding-inline: Spacings.$spacing03;
+ border-radius: Radius.$big;
+ width: fit-content;
+ font-size: Typography.$tiny;
+
+ &.primary {
+ background-color: Colors.$primary-light;
+ }
+
+ &.gold {
+ background-color: Colors.$gold;
+ }
+}
diff --git a/frontend/lib/components/ui/Tag/Tag.tsx b/frontend/lib/components/ui/Tag/Tag.tsx
new file mode 100644
index 000000000..4d465042c
--- /dev/null
+++ b/frontend/lib/components/ui/Tag/Tag.tsx
@@ -0,0 +1,16 @@
+import { Color } from "@/lib/types/Colors";
+
+import styles from "./Tag.module.scss";
+
+interface TagProps {
+ name: string;
+ color: Color;
+}
+
+export const Tag = (props: TagProps): JSX.Element => {
+ return (
+
+ {props.name}
+
+ );
+};
diff --git a/frontend/lib/context/BrainProvider/types.ts b/frontend/lib/context/BrainProvider/types.ts
index 5e462c4f8..2b20a54af 100644
--- a/frontend/lib/context/BrainProvider/types.ts
+++ b/frontend/lib/context/BrainProvider/types.ts
@@ -18,6 +18,7 @@ export type IntegrationDescription = {
integration_name: string;
integration_type: "custom" | "sync";
max_files: number;
+ allow_model_change: boolean;
};
export type Brain = {
@@ -45,6 +46,7 @@ export type MinimalBrainForUser = {
description: string;
integration_logo_url?: string;
max_files: number;
+ allow_model_change: boolean;
};
//TODO: rename rights to role in Backend and use MinimalBrainForUser instead of BackendMinimalBrainForUser
diff --git a/supabase/migrations/20240305225452_tags-integration.sql b/supabase/migrations/20240305225452_tags-integration.sql
new file mode 100644
index 000000000..c30ef962a
--- /dev/null
+++ b/supabase/migrations/20240305225452_tags-integration.sql
@@ -0,0 +1,7 @@
+create type "public"."brain_tags" as enum ('new', 'recommended', 'most_popular', 'premium', 'coming_soon', 'community', 'deprecated');
+
+alter table "public"."integrations" add column "information" text;
+
+alter table "public"."integrations" add column "tags" brain_tags[];
+
+
diff --git a/supabase/migrations/20240306013910_allow_model_change.sql b/supabase/migrations/20240306013910_allow_model_change.sql
new file mode 100644
index 000000000..21ef8afe0
--- /dev/null
+++ b/supabase/migrations/20240306013910_allow_model_change.sql
@@ -0,0 +1,3 @@
+alter table "public"."integrations" add column "allow_model_change" boolean not null default true;
+
+