Skip to content

Commit

Permalink
feat: finalise steps based brain creation (#1825)
Browse files Browse the repository at this point in the history
  • Loading branch information
mamadoudicko authored Dec 6, 2023
1 parent 5bbc72e commit 51de056
Show file tree
Hide file tree
Showing 34 changed files with 336 additions and 541 deletions.
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
import { UUID } from "crypto";

import { useKnowledgeToFeedInput } from "@/lib/components/KnowledgeToFeedInput/hooks/useKnowledgeToFeedInput.ts";
import { useKnowledgeToFeedFilesAndUrls } from "@/lib/hooks/useKnowledgeToFeed";
import { useOnboarding } from "@/lib/hooks/useOnboarding";

import { useKnowledgeToFeed } from "./useKnowledgeToFeed";

type FeedBrainProps = {
brainId: UUID;
chatId: UUID;
};
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export const useFeedBrainHandler = () => {
const { files, urls } = useKnowledgeToFeed();
const { files, urls } = useKnowledgeToFeedFilesAndUrls();
const { crawlWebsiteHandler, uploadFileHandler } = useKnowledgeToFeedInput();
const { updateOnboarding, onboarding } = useOnboarding();

Expand Down
2 changes: 1 addition & 1 deletion frontend/lib/api/brain/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export type ApiBrainDefinitionSchemaProperty = {
description: string;
name: string;
};
export const allowedRequestMethods = ["GET", "POST", "PUT", "DELETE"];
export const allowedRequestMethods = ["GET", "POST", "PUT", "DELETE"] as const;

export type AllowedRequestMethod = (typeof allowedRequestMethods)[number];

Expand Down
5 changes: 4 additions & 1 deletion frontend/lib/components/AddBrainModal/AddBrainModal.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { FormProvider, useForm } from "react-hook-form";

import { addBrainDefaultValues } from "@/lib/config/defaultBrainConfig";
import { KnowledgeToFeedProvider } from "@/lib/context";

import { AddBrainSteps } from "./components/AddBrainSteps/AddBrainSteps";
import { CreateBrainProps } from "./types";
Expand All @@ -24,7 +25,9 @@ export const AddBrainModal = ({

return (
<FormProvider {...methods}>
<AddBrainSteps triggerClassName={triggerClassName} />
<KnowledgeToFeedProvider>
<AddBrainSteps triggerClassName={triggerClassName} />
</KnowledgeToFeedProvider>
</FormProvider>
);
};
20 changes: 0 additions & 20 deletions frontend/lib/components/AddBrainModal/AddBrainModalSelector.tsx

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import Button from "@/lib/components/ui/Button";
import { Modal } from "@/lib/components/ui/Modal";
import { cn } from "@/lib/utils";

import { BrainKnowledgeStep } from "./components/BrainKnowledgeStep/BrainKnowledgeStep";
import { BrainParamsStep } from "./components/BrainParamsStep/BrainParamsStep";
import { BrainTypeSelectionStep } from "./components/BrainTypeSelectionStep/BrainTypeSelectionStep";
import { Stepper } from "./components/Stepper/Stepper";
Expand Down Expand Up @@ -54,6 +55,9 @@ export const AddBrainSteps = ({
<BrainParamsStep
onCancelBrainCreation={() => setIsBrainCreationModalOpened(false)}
/>
<BrainKnowledgeStep
onCancelBrainCreation={() => setIsBrainCreationModalOpened(false)}
/>
</form>
</Modal>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { Fragment } from "react";
import { useTranslation } from "react-i18next";
import { FaArrowLeft } from "react-icons/fa";

import { ApiRequestDefinition } from "@/lib/components/ApiRequestDefinition";
import Button from "@/lib/components/ui/Button";
import { BrainType } from "@/lib/types/brainConfig";

import { KnowledgeToFeedInput } from "./components/KnowledgeToFeedInput";
import { useBrainCreationHandler } from "./hooks/useBrainCreationHandler";
import { useBrainKnowledgeStep } from "./hooks/useBrainKnowledgeStep";
import { useBrainCreationSteps } from "../../hooks/useBrainCreationSteps";

type BrainKnowledgeStepProps = {
onCancelBrainCreation: () => void;
};

export const BrainKnowledgeStep = ({
onCancelBrainCreation,
}: BrainKnowledgeStepProps): JSX.Element => {
const { brainType, isSubmitButtonDisabled } = useBrainKnowledgeStep();
const { t } = useTranslation(["translation"]);
const { goToPreviousStep, currentStep } = useBrainCreationSteps();
const { handleCreateBrain, isBrainCreationPending } = useBrainCreationHandler(
{
closeBrainCreationModal: onCancelBrainCreation,
}
);

const brainTypeToKnowledgeComponent: Record<BrainType, JSX.Element> = {
doc: <KnowledgeToFeedInput />,
api: <ApiRequestDefinition />,
chatflow: <div>Coming soon</div>,
};

if (currentStep !== "KNOWLEDGE" || brainType === undefined) {
return <Fragment />;
}

return (
<>
{brainTypeToKnowledgeComponent[brainType]}
<div className="flex flex-row justify-between items-center flex-1 mt-10 w-full">
<Button
type="button"
variant="tertiary"
onClick={onCancelBrainCreation}
className="text-primary"
disabled={isBrainCreationPending}
>
{t("cancel", { ns: "translation" })}
</Button>
<div className="flex gap-4">
<Button
type="button"
variant="secondary"
onClick={goToPreviousStep}
className="py-2 border-primary text-primary"
disabled={isBrainCreationPending}
>
<FaArrowLeft className="text-xl" size={16} />
{t("previous", { ns: "translation" })}
</Button>

<Button
className="bg-primary text-white py-2 border-none"
type="button"
onClick={() => void handleCreateBrain()}
disabled={isSubmitButtonDisabled || isBrainCreationPending}
isLoading={isBrainCreationPending}
>
{t("createButton", { ns: "translation" })}
</Button>
</div>
</div>
</>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { useTranslation } from "react-i18next";

import {
Crawler,
FeedItems,
FileUploader,
} from "@/lib/components/KnowledgeToFeedInput/components";

export const KnowledgeToFeedInput = (): JSX.Element => {
const { t } = useTranslation(["translation", "upload"]);

return (
<div>
<div className="flex flex-row gap-10 justify-between items-center mt-5">
<FileUploader />
<span className="whitespace-nowrap ">
{`${t("and", { ns: "translation" })} / ${t("or", {
ns: "translation",
})}`}
</span>
<Crawler />
</div>
<FeedItems />
</div>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { UUID } from "crypto";
import { useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next";

import { PUBLIC_BRAINS_KEY } from "@/lib/api/brain/config";
import { useBrainApi } from "@/lib/api/brain/useBrainApi";
import { CreateBrainProps } from "@/lib/components/AddBrainModal/types";
import { useKnowledgeToFeedInput } from "@/lib/components/KnowledgeToFeedInput/hooks/useKnowledgeToFeedInput.ts";
import { useBrainContext } from "@/lib/context/BrainProvider/hooks/useBrainContext";
import { useKnowledgeToFeedContext } from "@/lib/context/KnowledgeToFeedProvider/hooks/useKnowledgeToFeedContext";
import { useToast } from "@/lib/hooks";
import { useKnowledgeToFeedFilesAndUrls } from "@/lib/hooks/useKnowledgeToFeed";

type UseBrainCreationHandler = {
closeBrainCreationModal: () => void;
};

// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export const useBrainCreationApi = ({
closeBrainCreationModal,
}: UseBrainCreationHandler) => {
const queryClient = useQueryClient();
const { publish } = useToast();
const { t } = useTranslation(["brain", "config"]);
const { files, urls } = useKnowledgeToFeedFilesAndUrls();
const { getValues, reset } = useFormContext<CreateBrainProps>();
const { setKnowledgeToFeed } = useKnowledgeToFeedContext();
const { createBrain: createBrainApi, setCurrentBrainId } = useBrainContext();
const { setAsDefaultBrain } = useBrainApi();
const { crawlWebsiteHandler, uploadFileHandler } = useKnowledgeToFeedInput();

const handleFeedBrain = async (brainId: UUID): Promise<void> => {
const uploadPromises = files.map((file) =>
uploadFileHandler(file, brainId)
);
const crawlPromises = urls.map((url) => crawlWebsiteHandler(url, brainId));

await Promise.all([...uploadPromises, ...crawlPromises]);
setKnowledgeToFeed([]);
};

const createBrain = async (): Promise<void> => {
const {
name,
description,
setDefault,
brain_definition,
brain_secrets_values,
status,
brain_type,
} = getValues();

const createdBrainId = await createBrainApi({
name,
description,
status,
brain_type,
brain_definition: brain_type === "api" ? brain_definition : undefined,
brain_secrets_values:
brain_type === "api" ? brain_secrets_values : undefined,
});

if (createdBrainId === undefined) {
publish({
variant: "danger",
text: t("errorCreatingBrain", { ns: "brain" }),
});

return;
}
if (brain_type === "doc") {
void handleFeedBrain(createdBrainId);
}

if (setDefault) {
await setAsDefaultBrain(createdBrainId);
}
setCurrentBrainId(createdBrainId);
closeBrainCreationModal();
reset();
void queryClient.invalidateQueries({
queryKey: [PUBLIC_BRAINS_KEY],
});
};

const { mutate, isPending: isBrainCreationPending } = useMutation({
mutationFn: createBrain,
onSuccess: () => {
publish({
variant: "success",
text: t("brainCreated", { ns: "brain" }),
});
},
});

return {
createBrain: mutate,
isBrainCreationPending,
};
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next";

import { CreateBrainProps } from "@/lib/components/AddBrainModal/types";
import { useToast } from "@/lib/hooks";

import { useBrainCreationApi } from "./useBrainCreationApi";

type UseBrainCreationHandler = {
closeBrainCreationModal: () => void;
};

// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export const useBrainCreationHandler = ({
closeBrainCreationModal,
}: UseBrainCreationHandler) => {
const { getValues } = useFormContext<CreateBrainProps>();
const { publish } = useToast();
const { t } = useTranslation(["brain", "config"]);

const { isBrainCreationPending, createBrain } = useBrainCreationApi({
closeBrainCreationModal,
});

const handleCreateBrain = () => {
const { name, description } = getValues();

if (name.trim() === "" || isBrainCreationPending) {
publish({
variant: "danger",
text: t("nameRequired", { ns: "config" }),
});

return;
}

if (description.trim() === "") {
publish({
variant: "danger",
text: t("descriptionRequired", { ns: "config" }),
});

return;
}
createBrain();
};

return {
handleCreateBrain,
isBrainCreationPending,
};
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { useFormContext } from "react-hook-form";

import { CreateBrainProps } from "@/lib/components/AddBrainModal/types";

// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export const useBrainKnowledgeStep = () => {
const { watch } = useFormContext<CreateBrainProps>();
const brainType = watch("brain_type");
const url = watch("brain_definition.url");
const isApiBrain = brainType === "api";
const isChatflowBrain = brainType === "chatflow";

const isApiBrainDefinitionsFilled = url !== "";

const isSubmitButtonDisabled =
isChatflowBrain || (isApiBrain && !isApiBrainDefinitionsFilled);

return {
brainType,
isSubmitButtonDisabled,
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import { Fragment } from "react";
import { useTranslation } from "react-i18next";
import { FaArrowLeft, FaArrowRight } from "react-icons/fa";

import { PublicAccessConfirmationModal } from "@/lib/components/AddBrainModalOld/components/AddBrainConfig/components/PublicAccessConfirmationModal";
import Button from "@/lib/components/ui/Button";
import Field from "@/lib/components/ui/Field";
import { Radio } from "@/lib/components/ui/Radio";
import { TextArea } from "@/lib/components/ui/TextArea";

import { PublicAccessConfirmationModal } from "./components/PublicAccessConfirmationModal";
import { useBrainParamsStep } from "./hooks/useBrainParamsStep";
import { useBrainStatusOptions } from "./hooks/useBrainStatusOptions";
import { usePublicAccessConfirmationModal } from "./hooks/usePublicAccessConfirmationModal";
Expand Down Expand Up @@ -53,6 +53,7 @@ export const BrainParamsStep = ({
placeholder={t("brainDescriptionPlaceholder", { ns: "brain" })}
autoComplete="off"
className="flex-1 m-3"
required
{...register("description")}
/>
<fieldset className="w-full flex flex-col">
Expand Down
Loading

0 comments on commit 51de056

Please sign in to comment.