mirror of
https://github.com/StanGirard/quivr.git
synced 2024-12-25 12:22:58 +03:00
feat: improve app ux (#1281)
* style: make FeedItemIcon the same size * feat: update feed component brain selector label position * style: change purple to 600 * feat: improve already dropped file message ux * feat: autoclose feedinput on chatId change * style: change chat colors * feat: prevent linebreak in knowledge to upload row * feat(textFIeld): avoid textfield content going under icon * feat(knowledgeToUpload): add tooltip on urls and files name * feat(feedBrain): auto scroll on messages when feed modal get opened * style: update colors * refactor: rename uploadCard to FeedCard
This commit is contained in:
parent
72ef62aad0
commit
36fd146fed
@ -88,7 +88,7 @@ export const SettingsTab = ({ brainId }: SettingsTabProps): JSX.Element => {
|
|||||||
<div className="mt-4">
|
<div className="mt-4">
|
||||||
<div className="flex flex-1 items-center flex-col">
|
<div className="flex flex-1 items-center flex-col">
|
||||||
{isPublicBrain && !isOwnedByCurrentUser && (
|
{isPublicBrain && !isOwnedByCurrentUser && (
|
||||||
<Chip className="mb-3 bg-purple-600 text-white w-full">
|
<Chip className="mb-3 bg-primary text-white w-full">
|
||||||
{t("brain:public_brain_label")}
|
{t("brain:public_brain_label")}
|
||||||
</Chip>
|
</Chip>
|
||||||
)}
|
)}
|
||||||
|
@ -71,7 +71,7 @@ export const BrainsList = (): JSX.Element => {
|
|||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
className="bg-purple-600 text-white py-2 mb-2 flex flex-row flex-1"
|
className="bg-primary text-white py-2 mb-2 flex flex-row flex-1"
|
||||||
>
|
>
|
||||||
{t("brain_management_button_label")}
|
{t("brain_management_button_label")}
|
||||||
</Button>
|
</Button>
|
||||||
@ -83,7 +83,7 @@ export const BrainsList = (): JSX.Element => {
|
|||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
className="bg-purple-600 text-white py-2 mb-2 flex flex-row flex-1"
|
className="bg-primary text-white py-2 mb-2 flex flex-row flex-1"
|
||||||
>
|
>
|
||||||
{t("brain_library_button_label")}
|
{t("brain_library_button_label")}
|
||||||
</Button>
|
</Button>
|
||||||
|
@ -36,7 +36,7 @@ export const PublicBrainItem = ({
|
|||||||
}}
|
}}
|
||||||
disabled={isUserSubscribedToBrain || subscriptionRequestPending}
|
disabled={isUserSubscribedToBrain || subscriptionRequestPending}
|
||||||
isLoading={subscriptionRequestPending}
|
isLoading={subscriptionRequestPending}
|
||||||
className="bg-purple-600 text-white p-0 px-3 rounded-xl border-0 w-content mt-3"
|
className="bg-primary text-white p-0 px-3 rounded-xl border-0 w-content mt-3"
|
||||||
>
|
>
|
||||||
{isUserSubscribedToBrain
|
{isUserSubscribedToBrain
|
||||||
? t("public_brain_already_subscribed_button_label")
|
? t("public_brain_already_subscribed_button_label")
|
||||||
|
@ -2,21 +2,16 @@ import { AnimatePresence, motion } from "framer-motion";
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { AiOutlineLoading3Quarters } from "react-icons/ai";
|
import { AiOutlineLoading3Quarters } from "react-icons/ai";
|
||||||
|
|
||||||
|
import { useKnowledgeToFeedContext } from "@/lib/context/KnowledgeToFeedProvider/hooks/useKnowledgeToFeedContext";
|
||||||
|
|
||||||
import { ChatInput, KnowledgeToFeed } from "./components";
|
import { ChatInput, KnowledgeToFeed } from "./components";
|
||||||
import { useActionBar } from "./hooks/useActionBar";
|
import { useActionBar } from "./hooks/useActionBar";
|
||||||
|
|
||||||
type ActionBarProps = {
|
export const ActionsBar = (): JSX.Element => {
|
||||||
setShouldDisplayUploadCard: (shouldDisplay: boolean) => void;
|
|
||||||
shouldDisplayUploadCard: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const ActionsBar = ({
|
|
||||||
setShouldDisplayUploadCard,
|
|
||||||
shouldDisplayUploadCard,
|
|
||||||
}: ActionBarProps): JSX.Element => {
|
|
||||||
const { hasPendingRequests, setHasPendingRequests } = useActionBar();
|
const { hasPendingRequests, setHasPendingRequests } = useActionBar();
|
||||||
|
|
||||||
const { t } = useTranslation(["chat"]);
|
const { t } = useTranslation(["chat"]);
|
||||||
|
const { shouldDisplayFeedCard } = useKnowledgeToFeedContext();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -30,7 +25,7 @@ export const ActionsBar = ({
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
{shouldDisplayUploadCard && (
|
{shouldDisplayFeedCard && (
|
||||||
<AnimatePresence>
|
<AnimatePresence>
|
||||||
<motion.div
|
<motion.div
|
||||||
key="slide"
|
key="slide"
|
||||||
@ -40,19 +35,15 @@ export const ActionsBar = ({
|
|||||||
>
|
>
|
||||||
<div className="flex flex-1 overflow-y-auto shadow-md dark:shadow-primary/25 hover:shadow-xl transition-shadow rounded-xl bg-white dark:bg-black border border-black/10 dark:border-white/25 p-4 md:p-6 mt-5">
|
<div className="flex flex-1 overflow-y-auto shadow-md dark:shadow-primary/25 hover:shadow-xl transition-shadow rounded-xl bg-white dark:bg-black border border-black/10 dark:border-white/25 p-4 md:p-6 mt-5">
|
||||||
<KnowledgeToFeed
|
<KnowledgeToFeed
|
||||||
closeFeedInput={() => setShouldDisplayUploadCard(false)}
|
|
||||||
dispatchHasPendingRequests={() => setHasPendingRequests(true)}
|
dispatchHasPendingRequests={() => setHasPendingRequests(true)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
</AnimatePresence>
|
</AnimatePresence>
|
||||||
)}
|
)}
|
||||||
{!shouldDisplayUploadCard && (
|
{!shouldDisplayFeedCard && (
|
||||||
<div className="flex mt-1 flex-col w-full shadow-md dark:shadow-primary/25 hover:shadow-xl transition-shadow rounded-xl bg-white dark:bg-black border border-black/10 dark:border-white/25 md:mb-4 lg:mb-[-20px] p-2">
|
<div className="flex mt-1 flex-col w-full shadow-md dark:shadow-primary/25 hover:shadow-xl transition-shadow rounded-xl bg-white dark:bg-black border border-black/10 dark:border-white/25 md:mb-4 lg:mb-[-20px] p-2">
|
||||||
<ChatInput
|
<ChatInput shouldDisplayFeedCard={shouldDisplayFeedCard} />
|
||||||
shouldDisplayUploadCard={shouldDisplayUploadCard}
|
|
||||||
setShouldDisplayUploadCard={setShouldDisplayUploadCard}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
@ -3,24 +3,25 @@ import { useTranslation } from "react-i18next";
|
|||||||
import { PiPaperclipFill } from "react-icons/pi";
|
import { PiPaperclipFill } from "react-icons/pi";
|
||||||
|
|
||||||
import Button from "@/lib/components/ui/Button";
|
import Button from "@/lib/components/ui/Button";
|
||||||
|
import { useKnowledgeToFeedContext } from "@/lib/context/KnowledgeToFeedProvider/hooks/useKnowledgeToFeedContext";
|
||||||
|
|
||||||
import { ChatBar } from "./components/ChatBar/ChatBar";
|
import { ChatBar } from "./components/ChatBar/ChatBar";
|
||||||
import { ConfigModal } from "./components/ConfigModal";
|
import { ConfigModal } from "./components/ConfigModal";
|
||||||
import { useChatInput } from "./hooks/useChatInput";
|
import { useChatInput } from "./hooks/useChatInput";
|
||||||
|
|
||||||
type ChatInputProps = {
|
type ChatInputProps = {
|
||||||
shouldDisplayUploadCard: boolean;
|
shouldDisplayFeedCard: boolean;
|
||||||
setShouldDisplayUploadCard: (shouldDisplayUploadCard: boolean) => void;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ChatInput = ({
|
export const ChatInput = ({
|
||||||
shouldDisplayUploadCard,
|
shouldDisplayFeedCard,
|
||||||
setShouldDisplayUploadCard,
|
|
||||||
}: ChatInputProps): JSX.Element => {
|
}: ChatInputProps): JSX.Element => {
|
||||||
const { setMessage, submitQuestion, generatingAnswer, message } =
|
const { setMessage, submitQuestion, generatingAnswer, message } =
|
||||||
useChatInput();
|
useChatInput();
|
||||||
const { t } = useTranslation(["chat"]);
|
const { t } = useTranslation(["chat"]);
|
||||||
|
|
||||||
|
const { setShouldDisplayFeedCard } = useKnowledgeToFeedContext();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form
|
<form
|
||||||
data-testid="chat-input-form"
|
data-testid="chat-input-form"
|
||||||
@ -30,13 +31,13 @@ export const ChatInput = ({
|
|||||||
}}
|
}}
|
||||||
className="sticky bottom-0 bg-white dark:bg-black w-full flex items-center gap-2 z-20 p-2"
|
className="sticky bottom-0 bg-white dark:bg-black w-full flex items-center gap-2 z-20 p-2"
|
||||||
>
|
>
|
||||||
{!shouldDisplayUploadCard && (
|
{!shouldDisplayFeedCard && (
|
||||||
<Button
|
<Button
|
||||||
className="p-0"
|
className="p-0"
|
||||||
variant={"tertiary"}
|
variant={"tertiary"}
|
||||||
data-testid="upload-button"
|
data-testid="upload-button"
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => setShouldDisplayUploadCard(true)}
|
onClick={() => setShouldDisplayFeedCard(true)}
|
||||||
tooltip={t("add_content_card_button_tooltip")}
|
tooltip={t("add_content_card_button_tooltip")}
|
||||||
>
|
>
|
||||||
<PiPaperclipFill className="text-3xl" />
|
<PiPaperclipFill className="text-3xl" />
|
||||||
|
@ -8,22 +8,23 @@ import Button from "@/lib/components/ui/Button";
|
|||||||
import { Select } from "@/lib/components/ui/Select";
|
import { Select } from "@/lib/components/ui/Select";
|
||||||
import { requiredRolesForUpload } from "@/lib/config/upload";
|
import { requiredRolesForUpload } from "@/lib/config/upload";
|
||||||
import { useBrainContext } from "@/lib/context/BrainProvider/hooks/useBrainContext";
|
import { useBrainContext } from "@/lib/context/BrainProvider/hooks/useBrainContext";
|
||||||
|
import { useKnowledgeToFeedContext } from "@/lib/context/KnowledgeToFeedProvider/hooks/useKnowledgeToFeedContext";
|
||||||
|
|
||||||
import { useFeedBrainInChat } from "./hooks/useFeedBrainInChat";
|
import { useFeedBrainInChat } from "./hooks/useFeedBrainInChat";
|
||||||
import { formatMinimalBrainsToSelectComponentInput } from "./utils/formatMinimalBrainsToSelectComponentInput";
|
import { formatMinimalBrainsToSelectComponentInput } from "./utils/formatMinimalBrainsToSelectComponentInput";
|
||||||
|
|
||||||
type KnowledgeToFeedProps = {
|
type KnowledgeToFeedProps = {
|
||||||
closeFeedInput: () => void;
|
dispatchHasPendingRequests: () => void;
|
||||||
dispatchHasPendingRequests?: () => void;
|
|
||||||
};
|
};
|
||||||
export const KnowledgeToFeed = ({
|
export const KnowledgeToFeed = ({
|
||||||
closeFeedInput,
|
|
||||||
dispatchHasPendingRequests,
|
dispatchHasPendingRequests,
|
||||||
}: KnowledgeToFeedProps): JSX.Element => {
|
}: KnowledgeToFeedProps): JSX.Element => {
|
||||||
const { allBrains, currentBrainId, setCurrentBrainId } = useBrainContext();
|
const { allBrains, currentBrainId, setCurrentBrainId } = useBrainContext();
|
||||||
|
|
||||||
const { t } = useTranslation(["upload"]);
|
const { t } = useTranslation(["upload"]);
|
||||||
|
|
||||||
|
const { setShouldDisplayFeedCard } = useKnowledgeToFeedContext();
|
||||||
|
|
||||||
const brainsWithUploadRights = useMemo(
|
const brainsWithUploadRights = useMemo(
|
||||||
() =>
|
() =>
|
||||||
allBrains.filter((brain) => requiredRolesForUpload.includes(brain.role)),
|
allBrains.filter((brain) => requiredRolesForUpload.includes(brain.role)),
|
||||||
@ -32,14 +33,16 @@ export const KnowledgeToFeed = ({
|
|||||||
|
|
||||||
const { feedBrain } = useFeedBrainInChat({
|
const { feedBrain } = useFeedBrainInChat({
|
||||||
dispatchHasPendingRequests,
|
dispatchHasPendingRequests,
|
||||||
closeFeedInput,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex-col w-full relative">
|
<div className="flex-col w-full relative">
|
||||||
<div className="flex flex-1 justify-between">
|
<div className="flex flex-1 justify-between">
|
||||||
<AddBrainModal />
|
<AddBrainModal />
|
||||||
<Button variant={"tertiary"} onClick={closeFeedInput}>
|
<Button
|
||||||
|
variant={"tertiary"}
|
||||||
|
onClick={() => setShouldDisplayFeedCard(false)}
|
||||||
|
>
|
||||||
<span>
|
<span>
|
||||||
<MdClose className="text-3xl" />
|
<MdClose className="text-3xl" />
|
||||||
</span>
|
</span>
|
||||||
@ -47,10 +50,10 @@ export const KnowledgeToFeed = ({
|
|||||||
</div>
|
</div>
|
||||||
<div className="flex justify-center">
|
<div className="flex justify-center">
|
||||||
<Select
|
<Select
|
||||||
label={t("selected_brain_select_label")}
|
|
||||||
options={formatMinimalBrainsToSelectComponentInput(
|
options={formatMinimalBrainsToSelectComponentInput(
|
||||||
brainsWithUploadRights
|
brainsWithUploadRights
|
||||||
)}
|
)}
|
||||||
|
emptyLabel={t("selected_brain_select_label")}
|
||||||
value={currentBrainId ?? undefined}
|
value={currentBrainId ?? undefined}
|
||||||
onChange={(newSelectedBrainId) =>
|
onChange={(newSelectedBrainId) =>
|
||||||
setCurrentBrainId(newSelectedBrainId)
|
setCurrentBrainId(newSelectedBrainId)
|
||||||
|
@ -16,14 +16,13 @@ import { FeedItemCrawlType, FeedItemUploadType } from "../../../types";
|
|||||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
||||||
export const useFeedBrainInChat = ({
|
export const useFeedBrainInChat = ({
|
||||||
dispatchHasPendingRequests,
|
dispatchHasPendingRequests,
|
||||||
closeFeedInput,
|
|
||||||
}: {
|
}: {
|
||||||
dispatchHasPendingRequests?: () => void;
|
dispatchHasPendingRequests: () => void;
|
||||||
closeFeedInput?: () => void;
|
|
||||||
}) => {
|
}) => {
|
||||||
const { publish } = useToast();
|
const { publish } = useToast();
|
||||||
const { t } = useTranslation(["upload"]);
|
const { t } = useTranslation(["upload"]);
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
const { setShouldDisplayFeedCard } = useKnowledgeToFeedContext();
|
||||||
|
|
||||||
const { currentBrainId } = useBrainContext();
|
const { currentBrainId } = useBrainContext();
|
||||||
const { setKnowledgeToFeed, knowledgeToFeed } = useKnowledgeToFeedContext();
|
const { setKnowledgeToFeed, knowledgeToFeed } = useKnowledgeToFeedContext();
|
||||||
@ -62,8 +61,8 @@ export const useFeedBrainInChat = ({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
dispatchHasPendingRequests?.();
|
dispatchHasPendingRequests();
|
||||||
closeFeedInput?.();
|
setShouldDisplayFeedCard(false);
|
||||||
setHasPendingRequests(true);
|
setHasPendingRequests(true);
|
||||||
const currentChatId = chatId ?? (await createChat("New Chat")).chat_id;
|
const currentChatId = chatId ?? (await createChat("New Chat")).chat_id;
|
||||||
const uploadPromises = files.map((file) =>
|
const uploadPromises = files.map((file) =>
|
||||||
|
@ -25,16 +25,16 @@ export const MessageRow = React.forwardRef(
|
|||||||
const handleCopy = () => {
|
const handleCopy = () => {
|
||||||
navigator.clipboard.writeText(text).then(
|
navigator.clipboard.writeText(text).then(
|
||||||
() => setIsCopied(true),
|
() => setIsCopied(true),
|
||||||
(err) => console.error('Failed to copy!', err)
|
(err) => console.error("Failed to copy!", err)
|
||||||
);
|
);
|
||||||
setTimeout(() => setIsCopied(false), 2000); // Reset after 2 seconds
|
setTimeout(() => setIsCopied(false), 2000); // Reset after 2 seconds
|
||||||
};
|
};
|
||||||
|
|
||||||
const containerClasses = cn(
|
const containerClasses = cn(
|
||||||
"py-3 px-5 w-fit",
|
"py-3 px-5 w-fit",
|
||||||
isUserSpeaker
|
isUserSpeaker
|
||||||
? "bg-gray-100 bg-opacity-60 items-start"
|
? "bg-msg-gray bg-opacity-60 items-start"
|
||||||
: "bg-purple-100 bg-opacity-60 items-end",
|
: "bg-msg-purple bg-opacity-60 items-end",
|
||||||
"dark:bg-gray-800 rounded-3xl flex flex-col overflow-hidden scroll-pb-32"
|
"dark:bg-gray-800 rounded-3xl flex flex-col overflow-hidden scroll-pb-32"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ import _debounce from "lodash/debounce";
|
|||||||
import { useCallback, useEffect, useRef } from "react";
|
import { useCallback, useEffect, useRef } from "react";
|
||||||
|
|
||||||
import { useChat } from "@/app/chat/[chatId]/hooks/useChat";
|
import { useChat } from "@/app/chat/[chatId]/hooks/useChat";
|
||||||
|
import { useKnowledgeToFeedContext } from "@/lib/context/KnowledgeToFeedProvider/hooks/useKnowledgeToFeedContext";
|
||||||
|
|
||||||
//TODO: link this to chat input to get the right height
|
//TODO: link this to chat input to get the right height
|
||||||
const chatInputHeightEstimation = 100;
|
const chatInputHeightEstimation = 100;
|
||||||
@ -10,6 +11,7 @@ const chatInputHeightEstimation = 100;
|
|||||||
export const useChatDialogue = () => {
|
export const useChatDialogue = () => {
|
||||||
const chatListRef = useRef<HTMLDivElement | null>(null);
|
const chatListRef = useRef<HTMLDivElement | null>(null);
|
||||||
const { messages } = useChat();
|
const { messages } = useChat();
|
||||||
|
const { shouldDisplayFeedCard } = useKnowledgeToFeedContext();
|
||||||
|
|
||||||
const scrollToBottom = useCallback(
|
const scrollToBottom = useCallback(
|
||||||
_debounce(() => {
|
_debounce(() => {
|
||||||
@ -43,7 +45,7 @@ export const useChatDialogue = () => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
scrollToBottom();
|
scrollToBottom();
|
||||||
}, [messages, scrollToBottom]);
|
}, [messages, scrollToBottom, shouldDisplayFeedCard]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
chatListRef,
|
chatListRef,
|
||||||
|
@ -22,6 +22,7 @@ export const ChatDialogue = ({
|
|||||||
flexDirection: "column",
|
flexDirection: "column",
|
||||||
flex: 1,
|
flex: 1,
|
||||||
overflowY: "auto",
|
overflowY: "auto",
|
||||||
|
marginBottom: 10,
|
||||||
}}
|
}}
|
||||||
ref={chatListRef}
|
ref={chatListRef}
|
||||||
>
|
>
|
||||||
|
@ -10,20 +10,19 @@ export const ChatHeader = (): JSX.Element => {
|
|||||||
return (
|
return (
|
||||||
<h1 className="hidden lg:block text-3xl font-bold text-center">
|
<h1 className="hidden lg:block text-3xl font-bold text-center">
|
||||||
{t("chat_title_intro")}{" "}
|
{t("chat_title_intro")}{" "}
|
||||||
<span className="text-purple-500">{t("brains")}</span>
|
<span className="text-primary">{t("brains")}</span>
|
||||||
</h1>
|
</h1>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<h1 className="hidden lg:block text-3xl font-bold text-center">
|
<h1 className="hidden lg:block text-3xl font-bold text-center">
|
||||||
{t("chat_title_intro")}{" "}
|
{t("chat_title_intro")}{" "}
|
||||||
|
<span className="text-primary">{t("brains")}</span>
|
||||||
<span className="text-purple-500">{t("brains")}</span>
|
|
||||||
{" !! "}
|
{" !! "}
|
||||||
<br />
|
<br />
|
||||||
{t("empty_brain_title_prefix")}{" "}
|
{t("empty_brain_title_prefix")}{" "}
|
||||||
<span className="text-purple-500">{t("brain")}</span>{" "}
|
<span className="text-primary">{t("brain")}</span>{" "}
|
||||||
{t("empty_brain_title_suffix")}
|
{t("empty_brain_title_suffix")}
|
||||||
</h1>
|
</h1>
|
||||||
);
|
);
|
||||||
|
@ -1,20 +0,0 @@
|
|||||||
import { useEffect, useState } from "react";
|
|
||||||
|
|
||||||
import { useKnowledgeToFeedContext } from "@/lib/context/KnowledgeToFeedProvider/hooks/useKnowledgeToFeedContext";
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
|
||||||
export const useSelectedChatPage = () => {
|
|
||||||
const [shouldDisplayUploadCard, setShouldDisplayUploadCard] = useState(false);
|
|
||||||
const { knowledgeToFeed } = useKnowledgeToFeedContext();
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (knowledgeToFeed.length > 0 && !shouldDisplayUploadCard) {
|
|
||||||
setShouldDisplayUploadCard(true);
|
|
||||||
}
|
|
||||||
}, [knowledgeToFeed, setShouldDisplayUploadCard]);
|
|
||||||
|
|
||||||
return {
|
|
||||||
shouldDisplayUploadCard,
|
|
||||||
setShouldDisplayUploadCard,
|
|
||||||
};
|
|
||||||
};
|
|
@ -1,16 +1,15 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
|
import { useKnowledgeToFeedContext } from "@/lib/context/KnowledgeToFeedProvider/hooks/useKnowledgeToFeedContext";
|
||||||
import { useCustomDropzone } from "@/lib/hooks/useDropzone";
|
import { useCustomDropzone } from "@/lib/hooks/useDropzone";
|
||||||
|
|
||||||
import { ActionsBar } from "./components/ActionsBar";
|
import { ActionsBar } from "./components/ActionsBar";
|
||||||
import { ChatDialogueArea } from "./components/ChatDialogueArea/ChatDialogue";
|
import { ChatDialogueArea } from "./components/ChatDialogueArea/ChatDialogue";
|
||||||
import { ChatHeader } from "./components/ChatHeader";
|
import { ChatHeader } from "./components/ChatHeader";
|
||||||
import { useSelectedChatPage } from "./hooks/useSelectedChatPage";
|
|
||||||
|
|
||||||
const SelectedChatPage = (): JSX.Element => {
|
const SelectedChatPage = (): JSX.Element => {
|
||||||
const { setShouldDisplayUploadCard, shouldDisplayUploadCard } =
|
|
||||||
useSelectedChatPage();
|
|
||||||
const { getRootProps } = useCustomDropzone();
|
const { getRootProps } = useCustomDropzone();
|
||||||
|
const { shouldDisplayFeedCard } = useKnowledgeToFeedContext();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main
|
<main
|
||||||
@ -22,16 +21,13 @@ const SelectedChatPage = (): JSX.Element => {
|
|||||||
<ChatHeader />
|
<ChatHeader />
|
||||||
<div
|
<div
|
||||||
className={`flex-1 flex flex-col mt-4 md:mt-8 w-full shadow-md dark:shadow-primary/25 hover:shadow-xl transition-shadow rounded-xl overflow-hidden dark:bg-black border border-black/10 dark:border-white/25 p-2 md:p-12 pt-4 md:pt-10 ${
|
className={`flex-1 flex flex-col mt-4 md:mt-8 w-full shadow-md dark:shadow-primary/25 hover:shadow-xl transition-shadow rounded-xl overflow-hidden dark:bg-black border border-black/10 dark:border-white/25 p-2 md:p-12 pt-4 md:pt-10 ${
|
||||||
shouldDisplayUploadCard ? "bg-gray-100" : "bg-white"
|
shouldDisplayFeedCard ? "bg-chat-bg-gray" : "bg-white"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<div className="flex flex-1 flex-col overflow-y-auto">
|
<div className="flex flex-1 flex-col overflow-y-auto">
|
||||||
<ChatDialogueArea />
|
<ChatDialogueArea />
|
||||||
</div>
|
</div>
|
||||||
<ActionsBar
|
<ActionsBar />
|
||||||
setShouldDisplayUploadCard={setShouldDisplayUploadCard}
|
|
||||||
shouldDisplayUploadCard={shouldDisplayUploadCard}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
|
@ -11,7 +11,9 @@ import {
|
|||||||
ChatContextMock,
|
ChatContextMock,
|
||||||
ChatProviderMock,
|
ChatProviderMock,
|
||||||
} from "@/lib/context/ChatProvider/mocks/ChatProviderMock";
|
} from "@/lib/context/ChatProvider/mocks/ChatProviderMock";
|
||||||
|
import { KnowledgeToFeedProvider } from "@/lib/context/KnowledgeToFeedProvider";
|
||||||
import { SupabaseContextMock } from "@/lib/context/SupabaseProvider/mocks/SupabaseProviderMock";
|
import { SupabaseContextMock } from "@/lib/context/SupabaseProvider/mocks/SupabaseProviderMock";
|
||||||
|
|
||||||
vi.mock("@/lib/context/SupabaseProvider/supabase-provider", () => ({
|
vi.mock("@/lib/context/SupabaseProvider/supabase-provider", () => ({
|
||||||
SupabaseContext: SupabaseContextMock,
|
SupabaseContext: SupabaseContextMock,
|
||||||
}));
|
}));
|
||||||
@ -89,11 +91,13 @@ describe("ChatsList", () => {
|
|||||||
it("should render correctly", () => {
|
it("should render correctly", () => {
|
||||||
const { getByTestId } = render(
|
const { getByTestId } = render(
|
||||||
<QueryClientProvider client={queryClient}>
|
<QueryClientProvider client={queryClient}>
|
||||||
<ChatProviderMock>
|
<KnowledgeToFeedProvider>
|
||||||
<BrainProviderMock>
|
<ChatProviderMock>
|
||||||
<ChatsList />
|
<BrainProviderMock>
|
||||||
</BrainProviderMock>
|
<ChatsList />
|
||||||
</ChatProviderMock>
|
</BrainProviderMock>
|
||||||
|
</ChatProviderMock>
|
||||||
|
</KnowledgeToFeedProvider>
|
||||||
</QueryClientProvider>
|
</QueryClientProvider>
|
||||||
);
|
);
|
||||||
const chatsList = getByTestId("chats-list");
|
const chatsList = getByTestId("chats-list");
|
||||||
@ -109,11 +113,13 @@ describe("ChatsList", () => {
|
|||||||
it("renders the chats list with correct number of items", () => {
|
it("renders the chats list with correct number of items", () => {
|
||||||
render(
|
render(
|
||||||
<QueryClientProvider client={queryClient}>
|
<QueryClientProvider client={queryClient}>
|
||||||
<ChatProviderMock>
|
<KnowledgeToFeedProvider>
|
||||||
<BrainProviderMock>
|
<ChatProviderMock>
|
||||||
<ChatsList />
|
<BrainProviderMock>
|
||||||
</BrainProviderMock>
|
<ChatsList />
|
||||||
</ChatProviderMock>
|
</BrainProviderMock>
|
||||||
|
</ChatProviderMock>
|
||||||
|
</KnowledgeToFeedProvider>
|
||||||
</QueryClientProvider>
|
</QueryClientProvider>
|
||||||
);
|
);
|
||||||
const chatItems = screen.getAllByTestId("chats-list-item");
|
const chatItems = screen.getAllByTestId("chats-list-item");
|
||||||
@ -129,11 +135,13 @@ describe("ChatsList", () => {
|
|||||||
await act(() =>
|
await act(() =>
|
||||||
render(
|
render(
|
||||||
<QueryClientProvider client={queryClient}>
|
<QueryClientProvider client={queryClient}>
|
||||||
<ChatProviderMock>
|
<KnowledgeToFeedProvider>
|
||||||
<BrainProviderMock>
|
<ChatProviderMock>
|
||||||
<ChatsList />
|
<BrainProviderMock>
|
||||||
</BrainProviderMock>
|
<ChatsList />
|
||||||
</ChatProviderMock>
|
</BrainProviderMock>
|
||||||
|
</ChatProviderMock>
|
||||||
|
</KnowledgeToFeedProvider>
|
||||||
</QueryClientProvider>
|
</QueryClientProvider>
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@ -155,11 +163,13 @@ describe("ChatsList", () => {
|
|||||||
await act(() =>
|
await act(() =>
|
||||||
render(
|
render(
|
||||||
<QueryClientProvider client={queryClient}>
|
<QueryClientProvider client={queryClient}>
|
||||||
<ChatProviderMock>
|
<KnowledgeToFeedProvider>
|
||||||
<BrainProviderMock>
|
<ChatProviderMock>
|
||||||
<ChatsList />
|
<BrainProviderMock>
|
||||||
</BrainProviderMock>
|
<ChatsList />
|
||||||
</ChatProviderMock>
|
</BrainProviderMock>
|
||||||
|
</ChatProviderMock>
|
||||||
|
</KnowledgeToFeedProvider>
|
||||||
</QueryClientProvider>
|
</QueryClientProvider>
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
@ -5,6 +5,7 @@ import { useEffect } from "react";
|
|||||||
import { useChatApi } from "@/lib/api/chat/useChatApi";
|
import { useChatApi } from "@/lib/api/chat/useChatApi";
|
||||||
import { useNotificationApi } from "@/lib/api/notification/useNotificationApi";
|
import { useNotificationApi } from "@/lib/api/notification/useNotificationApi";
|
||||||
import { useChatContext } from "@/lib/context";
|
import { useChatContext } from "@/lib/context";
|
||||||
|
import { useKnowledgeToFeedContext } from "@/lib/context/KnowledgeToFeedProvider/hooks/useKnowledgeToFeedContext";
|
||||||
|
|
||||||
import { getChatNotificationsQueryKey } from "../../../[chatId]/utils/getChatNotificationsQueryKey";
|
import { getChatNotificationsQueryKey } from "../../../[chatId]/utils/getChatNotificationsQueryKey";
|
||||||
import { getMessagesFromChatItems } from "../../../[chatId]/utils/getMessagesFromChatItems";
|
import { getMessagesFromChatItems } from "../../../[chatId]/utils/getMessagesFromChatItems";
|
||||||
@ -15,6 +16,7 @@ export const useChatNotificationsSync = () => {
|
|||||||
const { setMessages, setNotifications, notifications } = useChatContext();
|
const { setMessages, setNotifications, notifications } = useChatContext();
|
||||||
const { getChatItems } = useChatApi();
|
const { getChatItems } = useChatApi();
|
||||||
const { getChatNotifications } = useNotificationApi();
|
const { getChatNotifications } = useNotificationApi();
|
||||||
|
const { setShouldDisplayFeedCard } = useKnowledgeToFeedContext();
|
||||||
const params = useParams();
|
const params = useParams();
|
||||||
|
|
||||||
const chatId = params?.chatId as string | undefined;
|
const chatId = params?.chatId as string | undefined;
|
||||||
@ -54,6 +56,7 @@ export const useChatNotificationsSync = () => {
|
|||||||
}, [fetchedNotifications]);
|
}, [fetchedNotifications]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
setShouldDisplayFeedCard(false);
|
||||||
const fetchHistory = async () => {
|
const fetchHistory = async () => {
|
||||||
if (chatId === undefined) {
|
if (chatId === undefined) {
|
||||||
setMessages([]);
|
setMessages([]);
|
||||||
|
@ -31,7 +31,7 @@ export const KnowledgeToFeedInput = ({
|
|||||||
<div className="flex justify-center mt-5">
|
<div className="flex justify-center mt-5">
|
||||||
<Button
|
<Button
|
||||||
disabled={knowledgeToFeed.length === 0}
|
disabled={knowledgeToFeed.length === 0}
|
||||||
className="rounded-xl bg-purple-600 border-white"
|
className="rounded-xl bg-primary border-white"
|
||||||
onClick={() => void feedBrain()}
|
onClick={() => void feedBrain()}
|
||||||
>
|
>
|
||||||
{t("feed_form_submit_button", { ns: "upload" })}
|
{t("feed_form_submit_button", { ns: "upload" })}
|
||||||
|
@ -3,7 +3,7 @@ import { Fragment } from "react";
|
|||||||
import { useKnowledgeToFeedContext } from "@/lib/context/KnowledgeToFeedProvider/hooks/useKnowledgeToFeedContext";
|
import { useKnowledgeToFeedContext } from "@/lib/context/KnowledgeToFeedProvider/hooks/useKnowledgeToFeedContext";
|
||||||
|
|
||||||
import { CrawlFeedItem } from "./components/CrawlFeedItem";
|
import { CrawlFeedItem } from "./components/CrawlFeedItem";
|
||||||
import { FileFeedItem } from "./components/FileFeedItem/FileFeedItem";
|
import { FileFeedItem } from "./components/FileFeedItem";
|
||||||
|
|
||||||
export const FeedItems = (): JSX.Element => {
|
export const FeedItems = (): JSX.Element => {
|
||||||
const { knowledgeToFeed, removeKnowledgeToFeed } =
|
const { knowledgeToFeed, removeKnowledgeToFeed } =
|
||||||
|
@ -14,14 +14,20 @@ export const CrawlFeedItem = ({
|
|||||||
}: CrawlFeedItemProps): JSX.Element => {
|
}: CrawlFeedItemProps): JSX.Element => {
|
||||||
return (
|
return (
|
||||||
<StyledFeedItemDiv>
|
<StyledFeedItemDiv>
|
||||||
<div className="flex flex-1 items-center">
|
<div className="flex flex-1 overflow-hidden items-center gap-1">
|
||||||
<MdLink className="mr-2 text-2xl" />
|
<div>
|
||||||
<FeedTitleDisplayer title={url} />
|
<MdLink className="mr-2 text-2xl" />
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-1">
|
||||||
|
<FeedTitleDisplayer title={url} isUrl />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<IoMdCloseCircle
|
||||||
|
className="cursor-pointer text-gray-400 text-lg"
|
||||||
|
onClick={onRemove}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<IoMdCloseCircle
|
|
||||||
className="cursor-pointer text-gray-400 text-lg"
|
|
||||||
onClick={onRemove}
|
|
||||||
/>
|
|
||||||
</StyledFeedItemDiv>
|
</StyledFeedItemDiv>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,40 +1,24 @@
|
|||||||
import { useState } from "react";
|
import Tooltip from "@/lib/components/ui/Tooltip";
|
||||||
|
|
||||||
import { enhanceUrlDisplay } from "./utils/enhanceUrlDisplay";
|
import { enhanceUrlDisplay } from "./utils/enhanceUrlDisplay";
|
||||||
import { removeFileExtension } from "./utils/removeFileExtension";
|
import { removeFileExtension } from "./utils/removeFileExtension";
|
||||||
|
|
||||||
type FeedTitleDisplayerProps = {
|
type FeedTitleDisplayerProps = {
|
||||||
title: string;
|
title: string;
|
||||||
truncate?: boolean;
|
isUrl?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const FeedTitleDisplayer = ({
|
export const FeedTitleDisplayer = ({
|
||||||
title,
|
title,
|
||||||
truncate = false,
|
isUrl = false,
|
||||||
}: FeedTitleDisplayerProps): JSX.Element => {
|
}: FeedTitleDisplayerProps): JSX.Element => {
|
||||||
const [showFullUrl, setShowFullUrl] = useState(false);
|
|
||||||
|
|
||||||
const toggleShowFullUrl = () => {
|
|
||||||
setShowFullUrl(!showFullUrl);
|
|
||||||
};
|
|
||||||
|
|
||||||
if (truncate) {
|
|
||||||
return (
|
|
||||||
<div className="overflow-hidden">
|
|
||||||
<span className="cursor-pointer" onClick={toggleShowFullUrl}>
|
|
||||||
<p className={showFullUrl ? "" : "truncate"}>
|
|
||||||
{removeFileExtension(title)}
|
|
||||||
</p>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<span className="cursor-pointer" onClick={toggleShowFullUrl}>
|
<Tooltip tooltip={title}>
|
||||||
{showFullUrl ? title : enhanceUrlDisplay(title)}
|
<p className={`line-clamp-1 tooltip-${title}`}>
|
||||||
</span>
|
{isUrl ? enhanceUrlDisplay(title) : removeFileExtension(title)}
|
||||||
|
</p>
|
||||||
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -0,0 +1,35 @@
|
|||||||
|
import { IoMdCloseCircle } from "react-icons/io";
|
||||||
|
|
||||||
|
import { getFileIcon } from "@/lib/helpers/getFileIcon";
|
||||||
|
|
||||||
|
import { FeedTitleDisplayer } from "./FeedTitleDisplayer";
|
||||||
|
import { StyledFeedItemDiv } from "../styles/StyledFeedItemDiv";
|
||||||
|
|
||||||
|
type FileFeedItemProps = {
|
||||||
|
file: File;
|
||||||
|
onRemove: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const FileFeedItem = ({
|
||||||
|
file,
|
||||||
|
onRemove,
|
||||||
|
}: FileFeedItemProps): JSX.Element => {
|
||||||
|
const icon = getFileIcon(file.name);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<StyledFeedItemDiv>
|
||||||
|
<div className="flex flex-1 overflow-hidden items-center gap-1">
|
||||||
|
<div>{icon}</div>
|
||||||
|
<div className="flex flex-1">
|
||||||
|
<FeedTitleDisplayer title={file.name} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<IoMdCloseCircle
|
||||||
|
className="cursor-pointer text-gray-400 text-lg"
|
||||||
|
onClick={onRemove}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</StyledFeedItemDiv>
|
||||||
|
);
|
||||||
|
};
|
@ -1,31 +0,0 @@
|
|||||||
import { IoMdCloseCircle } from "react-icons/io";
|
|
||||||
|
|
||||||
import { getFileIcon } from "@/lib/helpers/getFileIcon";
|
|
||||||
|
|
||||||
import { StyledFeedItemDiv } from "../../styles/StyledFeedItemDiv";
|
|
||||||
import { FeedTitleDisplayer } from "../FeedTitleDisplayer";
|
|
||||||
|
|
||||||
type FileFeedItemProps = {
|
|
||||||
file: File;
|
|
||||||
onRemove: () => void;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const FileFeedItem = ({
|
|
||||||
file,
|
|
||||||
onRemove,
|
|
||||||
}: FileFeedItemProps): JSX.Element => {
|
|
||||||
const icon = getFileIcon(file.name);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<StyledFeedItemDiv>
|
|
||||||
<div className="flex flex-1 overflow-auto items-center gap-1">
|
|
||||||
{icon}
|
|
||||||
<FeedTitleDisplayer title={file.name} truncate />
|
|
||||||
</div>
|
|
||||||
<IoMdCloseCircle
|
|
||||||
className="cursor-pointer text-gray-400 text-lg"
|
|
||||||
onClick={onRemove}
|
|
||||||
/>
|
|
||||||
</StyledFeedItemDiv>
|
|
||||||
);
|
|
||||||
};
|
|
@ -1 +0,0 @@
|
|||||||
export * from "./FileFeedItem";
|
|
@ -10,7 +10,7 @@ export const StyledFeedItemDiv = ({
|
|||||||
<div
|
<div
|
||||||
{...propsWithoutClassname}
|
{...propsWithoutClassname}
|
||||||
className={cn(
|
className={cn(
|
||||||
"bg-gray-100 p-4 flex flex-row items-center py-2 rounded-lg shadow-sm ",
|
"bg-gray-100 p-4 flex flex-row items-center py-2 rounded-lg shadow-sm",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
@ -44,6 +44,7 @@ const Field = forwardRef(
|
|||||||
ref={forwardedRef as RefObject<HTMLInputElement>}
|
ref={forwardedRef as RefObject<HTMLInputElement>}
|
||||||
className={cn(
|
className={cn(
|
||||||
`w-full bg-gray-50 dark:bg-gray-900 px-4 py-2 border rounded-md border-black/10 dark:border-white/25`,
|
`w-full bg-gray-50 dark:bg-gray-900 px-4 py-2 border rounded-md border-black/10 dark:border-white/25`,
|
||||||
|
icon !== undefined ? "pr-12" : "",
|
||||||
inputClassName
|
inputClassName
|
||||||
)}
|
)}
|
||||||
name={name}
|
name={name}
|
||||||
|
@ -7,6 +7,8 @@ import { FeedItemType } from "@/app/chat/[chatId]/components/ActionsBar/types";
|
|||||||
type KnowledgeToFeedContextType = {
|
type KnowledgeToFeedContextType = {
|
||||||
knowledgeToFeed: FeedItemType[];
|
knowledgeToFeed: FeedItemType[];
|
||||||
setKnowledgeToFeed: React.Dispatch<React.SetStateAction<FeedItemType[]>>;
|
setKnowledgeToFeed: React.Dispatch<React.SetStateAction<FeedItemType[]>>;
|
||||||
|
shouldDisplayFeedCard: boolean;
|
||||||
|
setShouldDisplayFeedCard: React.Dispatch<React.SetStateAction<boolean>>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const KnowledgeToFeedContext = createContext<
|
export const KnowledgeToFeedContext = createContext<
|
||||||
@ -19,12 +21,15 @@ export const KnowledgeToFeedProvider = ({
|
|||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}): JSX.Element => {
|
}): JSX.Element => {
|
||||||
const [knowledgeToFeed, setKnowledgeToFeed] = useState<FeedItemType[]>([]);
|
const [knowledgeToFeed, setKnowledgeToFeed] = useState<FeedItemType[]>([]);
|
||||||
|
const [shouldDisplayFeedCard, setShouldDisplayFeedCard] = useState(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<KnowledgeToFeedContext.Provider
|
<KnowledgeToFeedContext.Provider
|
||||||
value={{
|
value={{
|
||||||
knowledgeToFeed,
|
knowledgeToFeed,
|
||||||
setKnowledgeToFeed,
|
setKnowledgeToFeed,
|
||||||
|
shouldDisplayFeedCard,
|
||||||
|
setShouldDisplayFeedCard,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
@ -4,14 +4,14 @@ import { useTranslation } from "react-i18next";
|
|||||||
import { FeedItemUploadType } from "@/app/chat/[chatId]/components/ActionsBar/types";
|
import { FeedItemUploadType } from "@/app/chat/[chatId]/components/ActionsBar/types";
|
||||||
import { useEventTracking } from "@/services/analytics/june/useEventTracking";
|
import { useEventTracking } from "@/services/analytics/june/useEventTracking";
|
||||||
|
|
||||||
|
|
||||||
import { useToast } from "./useToast";
|
import { useToast } from "./useToast";
|
||||||
import { useKnowledgeToFeedContext } from "../context/KnowledgeToFeedProvider/hooks/useKnowledgeToFeedContext";
|
import { useKnowledgeToFeedContext } from "../context/KnowledgeToFeedProvider/hooks/useKnowledgeToFeedContext";
|
||||||
import { acceptedFormats } from "../helpers/acceptedFormats";
|
import { acceptedFormats } from "../helpers/acceptedFormats";
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
||||||
export const useCustomDropzone = () => {
|
export const useCustomDropzone = () => {
|
||||||
const { knowledgeToFeed, addKnowledgeToFeed } = useKnowledgeToFeedContext();
|
const { knowledgeToFeed, addKnowledgeToFeed, setShouldDisplayFeedCard } =
|
||||||
|
useKnowledgeToFeedContext();
|
||||||
|
|
||||||
const files: File[] = (
|
const files: File[] = (
|
||||||
knowledgeToFeed.filter((c) => c.source === "upload") as FeedItemUploadType[]
|
knowledgeToFeed.filter((c) => c.source === "upload") as FeedItemUploadType[]
|
||||||
@ -23,6 +23,7 @@ export const useCustomDropzone = () => {
|
|||||||
const { t } = useTranslation(["upload"]);
|
const { t } = useTranslation(["upload"]);
|
||||||
|
|
||||||
const onDrop = (acceptedFiles: File[], fileRejections: FileRejection[]) => {
|
const onDrop = (acceptedFiles: File[], fileRejections: FileRejection[]) => {
|
||||||
|
setShouldDisplayFeedCard(true);
|
||||||
if (fileRejections.length > 0) {
|
if (fileRejections.length > 0) {
|
||||||
const firstRejection = fileRejections[0];
|
const firstRejection = fileRejections[0];
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
"private_brain_label": "Private",
|
"private_brain_label": "Private",
|
||||||
"public_brain_label": "Public",
|
"public_brain_label": "Public",
|
||||||
"brain_status_label":"Access",
|
"brain_status_label":"Access",
|
||||||
"set_brain_status_to_public_modal_title": "Are you sure you want to set this as <span class='text-purple-800'>Public</span>?<br/><br/>",
|
"set_brain_status_to_public_modal_title": "Are you sure you want to set this as <span class='text-primary'>Public</span>?<br/><br/>",
|
||||||
"set_brain_status_to_public_modal_description": "Every Quivr user will be able to:<br/>- Subscribe to your brain in the 'brains library'.<br/>- Use this brain and check the prompt and model configurations.<br/><br/>They won't have access to your uploaded files and people section.",
|
"set_brain_status_to_public_modal_description": "Every Quivr user will be able to:<br/>- Subscribe to your brain in the 'brains library'.<br/>- Use this brain and check the prompt and model configurations.<br/><br/>They won't have access to your uploaded files and people section.",
|
||||||
"confirm_set_brain_status_to_public": "Yes, set as public",
|
"confirm_set_brain_status_to_public": "Yes, set as public",
|
||||||
"cancel_set_brain_status_to_public": "No, keep it private",
|
"cancel_set_brain_status_to_public": "No, keep it private",
|
||||||
@ -41,7 +41,7 @@
|
|||||||
"public_brain_subscription_success_message":"You have successfully subscribed to the brain",
|
"public_brain_subscription_success_message":"You have successfully subscribed to the brain",
|
||||||
"public_brain_last_update_label":"Last update",
|
"public_brain_last_update_label":"Last update",
|
||||||
"public_brain_already_subscribed_button_label":"Subscribed",
|
"public_brain_already_subscribed_button_label":"Subscribed",
|
||||||
"set_brain_status_to_private_modal_title":"Are you sure you want to set this as <span class='text-purple-800'>Private</span>?<br/><br/>",
|
"set_brain_status_to_private_modal_title":"Are you sure you want to set this as <span class='text-primary'>Private</span>?<br/><br/>",
|
||||||
"set_brain_status_to_private_modal_description":"Every Quivr users won't be able to use this brain anymore and they won't see it in the brain library.",
|
"set_brain_status_to_private_modal_description":"Every Quivr users won't be able to use this brain anymore and they won't see it in the brain library.",
|
||||||
"confirm_set_brain_status_to_private":"Yes, set as private",
|
"confirm_set_brain_status_to_private":"Yes, set as private",
|
||||||
"cancel_set_brain_status_to_private":"No, keep it public",
|
"cancel_set_brain_status_to_private":"No, keep it public",
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
"success": "File uploaded successfully",
|
"success": "File uploaded successfully",
|
||||||
"uploadFailed": "Failed to upload file: {{message}}",
|
"uploadFailed": "Failed to upload file: {{message}}",
|
||||||
"maxSizeError": "File too big",
|
"maxSizeError": "File too big",
|
||||||
"alreadyAdded": "{{fileName}} was already added",
|
"alreadyAdded": "{{fileName}} was already added but not sent to your brain",
|
||||||
"addFiles": "Please, add files to upload",
|
"addFiles": "Please, add files to upload",
|
||||||
"selectBrain": "Please, select or create a brain to upload a file",
|
"selectBrain": "Please, select or create a brain to upload a file",
|
||||||
"invalidUrl": "Invalid URL",
|
"invalidUrl": "Invalid URL",
|
||||||
@ -16,5 +16,5 @@
|
|||||||
"missingNecessaryRole": "You don't have the necessary role to upload content to the selected brain. 🧠💡🥲",
|
"missingNecessaryRole": "You don't have the necessary role to upload content to the selected brain. 🧠💡🥲",
|
||||||
"invalidFileType": "Invalid file type",
|
"invalidFileType": "Invalid file type",
|
||||||
"feed_form_submit_button":"Send to my brain",
|
"feed_form_submit_button":"Send to my brain",
|
||||||
"selected_brain_select_label":"Brain selected"
|
"selected_brain_select_label":"Select a brain"
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
"private_brain_label": "Privado",
|
"private_brain_label": "Privado",
|
||||||
"public_brain_label": "Público",
|
"public_brain_label": "Público",
|
||||||
"brain_status_label": "Estado",
|
"brain_status_label": "Estado",
|
||||||
"set_brain_status_to_public_modal_title": "¿Estás seguro de querer establecer esto como <span class='text-purple-800'>Público</span>?<br/><br/>",
|
"set_brain_status_to_public_modal_title": "¿Estás seguro de querer establecer esto como <span class='text-primary'>Público</span>?<br/><br/>",
|
||||||
"set_brain_status_to_public_modal_description": "Cada usuario de Quivr podrá:<br/>- Suscribirse a tu cerebro en la 'biblioteca de cerebros'.<br/>- Usar este cerebro y comprobar las configuraciones de las indicaciones y el modelo.<br/><br/>No tendrán acceso a tus archivos cargados ni a la sección de personas.",
|
"set_brain_status_to_public_modal_description": "Cada usuario de Quivr podrá:<br/>- Suscribirse a tu cerebro en la 'biblioteca de cerebros'.<br/>- Usar este cerebro y comprobar las configuraciones de las indicaciones y el modelo.<br/><br/>No tendrán acceso a tus archivos cargados ni a la sección de personas.",
|
||||||
"confirm_set_brain_status_to_public": "Sí, establecer como público",
|
"confirm_set_brain_status_to_public": "Sí, establecer como público",
|
||||||
"cancel_set_brain_status_to_public": "No, mantenerlo privado",
|
"cancel_set_brain_status_to_public": "No, mantenerlo privado",
|
||||||
@ -40,7 +40,7 @@
|
|||||||
"public_brain_subscription_success_message": "Te has suscrito con éxito al cerebro",
|
"public_brain_subscription_success_message": "Te has suscrito con éxito al cerebro",
|
||||||
"public_brain_last_update_label": "Última actualización",
|
"public_brain_last_update_label": "Última actualización",
|
||||||
"public_brain_already_subscribed_button_label": "Ya suscrito",
|
"public_brain_already_subscribed_button_label": "Ya suscrito",
|
||||||
"set_brain_status_to_private_modal_title": "¿Estás seguro de que quieres establecer esto como <span class='text-purple-800'>Privado</span>?<br/><br/>",
|
"set_brain_status_to_private_modal_title": "¿Estás seguro de que quieres establecer esto como <span class='text-primary'>Privado</span>?<br/><br/>",
|
||||||
"set_brain_status_to_private_modal_description": "Los usuarios de Quivr ya no podrán utilizar este cerebro y no lo verán en la biblioteca de cerebros.",
|
"set_brain_status_to_private_modal_description": "Los usuarios de Quivr ya no podrán utilizar este cerebro y no lo verán en la biblioteca de cerebros.",
|
||||||
"confirm_set_brain_status_to_private": "Sí, establecer como privado",
|
"confirm_set_brain_status_to_private": "Sí, establecer como privado",
|
||||||
"cancel_set_brain_status_to_private": "No, mantenerlo público",
|
"cancel_set_brain_status_to_private": "No, mantenerlo público",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"addFiles": "Por favor, agregar archivos a subir",
|
"addFiles": "Por favor, agregar archivos a subir",
|
||||||
"alreadyAdded": "{{fileName}} ya fue agregado",
|
"alreadyAdded": "Ya se agregó {{fileName}} pero no se envió a tu cerebro.",
|
||||||
"crawlFailed": "Error al rastrear sitio web: {{message}}",
|
"crawlFailed": "Error al rastrear sitio web: {{message}}",
|
||||||
"drop": "Suelte los archivos aquí...",
|
"drop": "Suelte los archivos aquí...",
|
||||||
"uploadFailed": "Error al subir archivo: {{message}}",
|
"uploadFailed": "Error al subir archivo: {{message}}",
|
||||||
@ -16,5 +16,5 @@
|
|||||||
"webSite": "Ingrese la URL del sitio web",
|
"webSite": "Ingrese la URL del sitio web",
|
||||||
"invalidFileType": "Tipo de archivo no permitido",
|
"invalidFileType": "Tipo de archivo no permitido",
|
||||||
"feed_form_submit_button": "Enviar a mi cerebro",
|
"feed_form_submit_button": "Enviar a mi cerebro",
|
||||||
"selected_brain_select_label": "Cerebro seleccionado"
|
"selected_brain_select_label": "Seleccionar un cerebro"
|
||||||
}
|
}
|
@ -30,7 +30,7 @@
|
|||||||
"private_brain_label": "Privé",
|
"private_brain_label": "Privé",
|
||||||
"public_brain_label": "Public",
|
"public_brain_label": "Public",
|
||||||
"brain_status_label": "Statut",
|
"brain_status_label": "Statut",
|
||||||
"set_brain_status_to_public_modal_title": "Êtes-vous sûr de vouloir définir ceci comme <span class='text-purple-800'>Public</span>?<br/><br/>",
|
"set_brain_status_to_public_modal_title": "Êtes-vous sûr de vouloir définir ceci comme <span class='text-primary'>Public</span>?<br/><br/>",
|
||||||
"set_brain_status_to_public_modal_description": "Chaque utilisateur de Quivr pourra :<br/>- S'abonner à votre cerveau dans la 'bibliothèque des cerveaux'.<br/>- Utiliser ce cerveau et vérifier les configurations de prompts et de modèles.<br/><br/>Ils n'auront pas accès à vos fichiers téléchargés et à la section des personnes.",
|
"set_brain_status_to_public_modal_description": "Chaque utilisateur de Quivr pourra :<br/>- S'abonner à votre cerveau dans la 'bibliothèque des cerveaux'.<br/>- Utiliser ce cerveau et vérifier les configurations de prompts et de modèles.<br/><br/>Ils n'auront pas accès à vos fichiers téléchargés et à la section des personnes.",
|
||||||
"confirm_set_brain_status_to_public": "Oui, définir comme public",
|
"confirm_set_brain_status_to_public": "Oui, définir comme public",
|
||||||
"cancel_set_brain_status_to_public": "Non, le garder privé",
|
"cancel_set_brain_status_to_public": "Non, le garder privé",
|
||||||
@ -40,7 +40,7 @@
|
|||||||
"public_brain_subscription_success_message": "Vous vous êtes abonné avec succès au cerveau",
|
"public_brain_subscription_success_message": "Vous vous êtes abonné avec succès au cerveau",
|
||||||
"public_brain_last_update_label": "Dernière mise à jour",
|
"public_brain_last_update_label": "Dernière mise à jour",
|
||||||
"public_brain_already_subscribed_button_label": "Abonné",
|
"public_brain_already_subscribed_button_label": "Abonné",
|
||||||
"set_brain_status_to_private_modal_title": "Êtes-vous sûr de vouloir définir ceci comme <span class='text-purple-800'>Privé</span>?<br/><br/>",
|
"set_brain_status_to_private_modal_title": "Êtes-vous sûr de vouloir définir ceci comme <span class='text-primary'>Privé</span>?<br/><br/>",
|
||||||
"set_brain_status_to_private_modal_description": "Les utilisateurs de Quivr ne pourront plus utiliser ce cerveau et ne le verront plus dans la bibliothèque des cerveaux.",
|
"set_brain_status_to_private_modal_description": "Les utilisateurs de Quivr ne pourront plus utiliser ce cerveau et ne le verront plus dans la bibliothèque des cerveaux.",
|
||||||
"confirm_set_brain_status_to_private": "Oui, définir comme privé",
|
"confirm_set_brain_status_to_private": "Oui, définir comme privé",
|
||||||
"cancel_set_brain_status_to_private": "Non, le laisser public",
|
"cancel_set_brain_status_to_private": "Non, le laisser public",
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
"success": "Fichier téléchargé avec succès",
|
"success": "Fichier téléchargé avec succès",
|
||||||
"uploadFailed": "Échec du téléchargement du fichier : {{message}}",
|
"uploadFailed": "Échec du téléchargement du fichier : {{message}}",
|
||||||
"maxSizeError": "Fichier trop volumineux",
|
"maxSizeError": "Fichier trop volumineux",
|
||||||
"alreadyAdded": "{{fileName}} a déjà été ajouté",
|
"alreadyAdded": "{{fileName}} a déjà été ajouté mais n'a pas été envoyé à votre cerveau.",
|
||||||
"addFiles": "Veuillez ajouter des fichiers à télécharger",
|
"addFiles": "Veuillez ajouter des fichiers à télécharger",
|
||||||
"selectBrain": "Veuillez sélectionner ou créer un cerveau pour télécharger un fichier",
|
"selectBrain": "Veuillez sélectionner ou créer un cerveau pour télécharger un fichier",
|
||||||
"invalidUrl": "URL invalide",
|
"invalidUrl": "URL invalide",
|
||||||
@ -16,5 +16,5 @@
|
|||||||
"missingNecessaryRole": "Vous n'avez pas le rôle nécessaire pour télécharger du contenu dans le cerveau sélectionné. 🧠💡🥲",
|
"missingNecessaryRole": "Vous n'avez pas le rôle nécessaire pour télécharger du contenu dans le cerveau sélectionné. 🧠💡🥲",
|
||||||
"invalidFileType": "Type de fichier invalide",
|
"invalidFileType": "Type de fichier invalide",
|
||||||
"feed_form_submit_button":"Envoyer à mon cerveau",
|
"feed_form_submit_button":"Envoyer à mon cerveau",
|
||||||
"selected_brain_select_label": "Cerveau sélectionné"
|
"selected_brain_select_label": "Sélectionnez un cerveau"
|
||||||
}
|
}
|
@ -30,7 +30,7 @@
|
|||||||
"private_brain_label": "Privado",
|
"private_brain_label": "Privado",
|
||||||
"public_brain_label": "Público",
|
"public_brain_label": "Público",
|
||||||
"brain_status_label": "Status",
|
"brain_status_label": "Status",
|
||||||
"set_brain_status_to_public_modal_title": "Tem certeza de que deseja definir isso como <span class='text-purple-800'>Público</span>?<br/><br/>",
|
"set_brain_status_to_public_modal_title": "Tem certeza de que deseja definir isso como <span class='text-primary'>Público</span>?<br/><br/>",
|
||||||
"set_brain_status_to_public_modal_description": "Cada usuário do Quivr poderá:<br/>- Se inscrever em seu cérebro na 'biblioteca de cérebros'.<br/>- Usar este cérebro e verificar as configurações de prompts e modelos.<br/><br/>Eles não terão acesso aos seus arquivos enviados e à seção de pessoas.",
|
"set_brain_status_to_public_modal_description": "Cada usuário do Quivr poderá:<br/>- Se inscrever em seu cérebro na 'biblioteca de cérebros'.<br/>- Usar este cérebro e verificar as configurações de prompts e modelos.<br/><br/>Eles não terão acesso aos seus arquivos enviados e à seção de pessoas.",
|
||||||
"confirm_set_brain_status_to_public": "Sim, definir como público",
|
"confirm_set_brain_status_to_public": "Sim, definir como público",
|
||||||
"cancel_set_brain_status_to_public": "Não, mantê-lo privado",
|
"cancel_set_brain_status_to_public": "Não, mantê-lo privado",
|
||||||
@ -40,7 +40,7 @@
|
|||||||
"public_brain_subscription_success_message": "Você se inscreveu com sucesso no cérebro",
|
"public_brain_subscription_success_message": "Você se inscreveu com sucesso no cérebro",
|
||||||
"public_brain_last_update_label": "Última atualização",
|
"public_brain_last_update_label": "Última atualização",
|
||||||
"public_brain_already_subscribed_button_label": "Inscrito",
|
"public_brain_already_subscribed_button_label": "Inscrito",
|
||||||
"set_brain_status_to_private_modal_title": "Tem a certeza de que deseja definir isto como <span class='text-purple-800'>Privado</span>?<br/><br/>",
|
"set_brain_status_to_private_modal_title": "Tem a certeza de que deseja definir isto como <span class='text-primary'>Privado</span>?<br/><br/>",
|
||||||
"set_brain_status_to_private_modal_description": "Os utilizadores do Quivr não poderão mais utilizar este cérebro e não o verão na biblioteca de cérebros.",
|
"set_brain_status_to_private_modal_description": "Os utilizadores do Quivr não poderão mais utilizar este cérebro e não o verão na biblioteca de cérebros.",
|
||||||
"confirm_set_brain_status_to_private": "Sim, definir como privado",
|
"confirm_set_brain_status_to_private": "Sim, definir como privado",
|
||||||
"cancel_set_brain_status_to_private": "Não, mantê-lo público",
|
"cancel_set_brain_status_to_private": "Não, mantê-lo público",
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
"success": "Arquivo enviado com sucesso",
|
"success": "Arquivo enviado com sucesso",
|
||||||
"uploadFailed": "Falha ao enviar arquivo: {{message}}",
|
"uploadFailed": "Falha ao enviar arquivo: {{message}}",
|
||||||
"maxSizeError": "Arquivo muito grande",
|
"maxSizeError": "Arquivo muito grande",
|
||||||
"alreadyAdded": "{{fileName}} já foi adicionado",
|
"alreadyAdded": "{{fileName}} já foi adicionado, mas não foi enviado para o seu cérebro.",
|
||||||
"addFiles": "Por favor, adicione arquivos para enviar",
|
"addFiles": "Por favor, adicione arquivos para enviar",
|
||||||
"selectBrain": "Por favor, selecione ou crie um cérebro para enviar um arquivo",
|
"selectBrain": "Por favor, selecione ou crie um cérebro para enviar um arquivo",
|
||||||
"invalidUrl": "URL inválido",
|
"invalidUrl": "URL inválido",
|
||||||
@ -16,5 +16,5 @@
|
|||||||
"missingNecessaryRole": "Você não possui a função necessária para enviar conteúdo para o cérebro selecionado. 🧠💡🥲",
|
"missingNecessaryRole": "Você não possui a função necessária para enviar conteúdo para o cérebro selecionado. 🧠💡🥲",
|
||||||
"invalidFileType": "Tipo de arquivo inválido",
|
"invalidFileType": "Tipo de arquivo inválido",
|
||||||
"feed_form_submit_button": "Enviar para o meu cérebro",
|
"feed_form_submit_button": "Enviar para o meu cérebro",
|
||||||
"selected_brain_select_label": "Cérebro selecionado"
|
"selected_brain_select_label": "Selecione um cérebro"
|
||||||
}
|
}
|
@ -30,7 +30,7 @@
|
|||||||
"private_brain_label": "Приватный",
|
"private_brain_label": "Приватный",
|
||||||
"public_brain_label": "Публичный",
|
"public_brain_label": "Публичный",
|
||||||
"brain_status_label": "Статус",
|
"brain_status_label": "Статус",
|
||||||
"set_brain_status_to_public_modal_title": "Вы уверены, что хотите установить это как <span class='text-purple-800'>Публичный</span>?<br/><br/>",
|
"set_brain_status_to_public_modal_title": "Вы уверены, что хотите установить это как <span class='text-primary'>Публичный</span>?<br/><br/>",
|
||||||
"set_brain_status_to_public_modal_description": "Каждый пользователь Quivr сможет:<br/>- Подписаться на ваш мозг в 'библиотеке мозгов'.<br/>- Использовать этот мозг и проверить настройки подсказок и модели.<br/><br/>У них не будет доступа к вашим загруженным файлам и разделу 'люди'.",
|
"set_brain_status_to_public_modal_description": "Каждый пользователь Quivr сможет:<br/>- Подписаться на ваш мозг в 'библиотеке мозгов'.<br/>- Использовать этот мозг и проверить настройки подсказок и модели.<br/><br/>У них не будет доступа к вашим загруженным файлам и разделу 'люди'.",
|
||||||
"confirm_set_brain_status_to_public": "Да, установить как публичный",
|
"confirm_set_brain_status_to_public": "Да, установить как публичный",
|
||||||
"cancel_set_brain_status_to_public": "Нет, оставить приватным",
|
"cancel_set_brain_status_to_public": "Нет, оставить приватным",
|
||||||
@ -40,7 +40,7 @@
|
|||||||
"public_brain_subscription_success_message": "Вы успешно подписались на мозг",
|
"public_brain_subscription_success_message": "Вы успешно подписались на мозг",
|
||||||
"public_brain_last_update_label": "Последнее обновление",
|
"public_brain_last_update_label": "Последнее обновление",
|
||||||
"public_brain_already_subscribed_button_label": "Вы уже подписаны",
|
"public_brain_already_subscribed_button_label": "Вы уже подписаны",
|
||||||
"set_brain_status_to_private_modal_title": "Вы уверены, что хотите установить это как <span class='text-purple-800'>Частное</span>?<br/><br/>",
|
"set_brain_status_to_private_modal_title": "Вы уверены, что хотите установить это как <span class='text-primary'>Частное</span>?<br/><br/>",
|
||||||
"set_brain_status_to_private_modal_description": "Пользователи Quivr больше не смогут использовать этот мозг, и они не увидят его в библиотеке мозгов.",
|
"set_brain_status_to_private_modal_description": "Пользователи Quivr больше не смогут использовать этот мозг, и они не увидят его в библиотеке мозгов.",
|
||||||
"confirm_set_brain_status_to_private": "Да, установить как частное",
|
"confirm_set_brain_status_to_private": "Да, установить как частное",
|
||||||
"cancel_set_brain_status_to_private": "Нет, оставить общедоступным",
|
"cancel_set_brain_status_to_private": "Нет, оставить общедоступным",
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
"success": "Файл успешно загружен",
|
"success": "Файл успешно загружен",
|
||||||
"uploadFailed": "Не удалось загрузить файл: {{message}}",
|
"uploadFailed": "Не удалось загрузить файл: {{message}}",
|
||||||
"maxSizeError": "Файл слишком большой",
|
"maxSizeError": "Файл слишком большой",
|
||||||
"alreadyAdded": "{{fileName}} уже добавлен",
|
"alreadyAdded": "{{fileName}} уже добавлен, но не отправлен в ваш мозг.",
|
||||||
"addFiles": "Пожалуйста, добавьте файлы для загрузки",
|
"addFiles": "Пожалуйста, добавьте файлы для загрузки",
|
||||||
"selectBrain": "Пожалуйста, выберите или создайте мозг для загрузки файла",
|
"selectBrain": "Пожалуйста, выберите или создайте мозг для загрузки файла",
|
||||||
"invalidUrl": "Неверный URL",
|
"invalidUrl": "Неверный URL",
|
||||||
@ -16,5 +16,5 @@
|
|||||||
"missingNecessaryRole": "У вас нет необходимой роли для загрузки контента в выбранный мозг. 🧠💡🥲",
|
"missingNecessaryRole": "У вас нет необходимой роли для загрузки контента в выбранный мозг. 🧠💡🥲",
|
||||||
"invalidFileType": "Неверный тип файла",
|
"invalidFileType": "Неверный тип файла",
|
||||||
"feed_form_submit_button": "Отправить в мой мозг",
|
"feed_form_submit_button": "Отправить в мой мозг",
|
||||||
"selected_brain_select_label": "Выбран мозг"
|
"selected_brain_select_label": "Выберите мозг"
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
"private_brain_label": "私有",
|
"private_brain_label": "私有",
|
||||||
"public_brain_label": "公开",
|
"public_brain_label": "公开",
|
||||||
"brain_status_label": "状态",
|
"brain_status_label": "状态",
|
||||||
"set_brain_status_to_public_modal_title": "您确定要将此设置为<span class='text-purple-800'>公共</span>吗?<br/><br/>",
|
"set_brain_status_to_public_modal_title": "您确定要将此设置为<span class='text-primary'>公共</span>吗?<br/><br/>",
|
||||||
"set_brain_status_to_public_modal_description": "每个 Quivr 用户将能够:<br/>- 在 '大脑库' 中订阅您的大脑。<br/>- 使用此大脑并检查提示和模型配置。<br/><br/>他们将无法访问您上传的文件和人员部分。",
|
"set_brain_status_to_public_modal_description": "每个 Quivr 用户将能够:<br/>- 在 '大脑库' 中订阅您的大脑。<br/>- 使用此大脑并检查提示和模型配置。<br/><br/>他们将无法访问您上传的文件和人员部分。",
|
||||||
"confirm_set_brain_status_to_public": "是的,设为公共",
|
"confirm_set_brain_status_to_public": "是的,设为公共",
|
||||||
"cancel_set_brain_status_to_public": "不,保持私密",
|
"cancel_set_brain_status_to_public": "不,保持私密",
|
||||||
@ -40,7 +40,7 @@
|
|||||||
"public_brain_subscription_success_message": "Вы успешно подписались на мозг",
|
"public_brain_subscription_success_message": "Вы успешно подписались на мозг",
|
||||||
"public_brain_last_update_label": "Последнее обновление",
|
"public_brain_last_update_label": "Последнее обновление",
|
||||||
"public_brain_already_subscribed_button_label": "已订阅",
|
"public_brain_already_subscribed_button_label": "已订阅",
|
||||||
"set_brain_status_to_private_modal_title": "您确定要将此设置为<span class='text-purple-800'>私有</span>吗?<br/><br/>",
|
"set_brain_status_to_private_modal_title": "您确定要将此设置为<span class='text-primary'>私有</span>吗?<br/><br/>",
|
||||||
"set_brain_status_to_private_modal_description": "Quivr的用户将无法再使用此大脑,并且不会在大脑库中看到它。",
|
"set_brain_status_to_private_modal_description": "Quivr的用户将无法再使用此大脑,并且不会在大脑库中看到它。",
|
||||||
"confirm_set_brain_status_to_private": "是的,设为私有",
|
"confirm_set_brain_status_to_private": "是的,设为私有",
|
||||||
"cancel_set_brain_status_to_private": "不,保持为公开",
|
"cancel_set_brain_status_to_private": "不,保持为公开",
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
"success": "文件上传成功",
|
"success": "文件上传成功",
|
||||||
"uploadFailed": "上传文件失败:{{message}}",
|
"uploadFailed": "上传文件失败:{{message}}",
|
||||||
"maxSizeError": "文件太大",
|
"maxSizeError": "文件太大",
|
||||||
"alreadyAdded": "已添加 {{filename}}",
|
"alreadyAdded": "{{fileName}} 已经添加,但尚未发送到您的大脑。",
|
||||||
"addFiles": "请添加要上传的文件",
|
"addFiles": "请添加要上传的文件",
|
||||||
"selectBrain": "请选择或创建一个大脑来上传文件。",
|
"selectBrain": "请选择或创建一个大脑来上传文件。",
|
||||||
"invalidUrl": "无效的URL",
|
"invalidUrl": "无效的URL",
|
||||||
@ -16,5 +16,5 @@
|
|||||||
"missingNecessaryRole": "您没有所选大脑的上传权限。 🧠💡🥲",
|
"missingNecessaryRole": "您没有所选大脑的上传权限。 🧠💡🥲",
|
||||||
"invalidFileType": "文件类型不受支持",
|
"invalidFileType": "文件类型不受支持",
|
||||||
"feed_form_submit_button":"发送到我的大脑",
|
"feed_form_submit_button":"发送到我的大脑",
|
||||||
"selected_brain_select_label": "已选择的大脑"
|
"selected_brain_select_label": "选择一个大脑"
|
||||||
}
|
}
|
@ -17,6 +17,9 @@ module.exports = {
|
|||||||
colors: {
|
colors: {
|
||||||
black: "#00121F",
|
black: "#00121F",
|
||||||
primary: "#4F46E5",
|
primary: "#4F46E5",
|
||||||
|
"chat-bg-gray": "#D9D9D9",
|
||||||
|
"msg-gray": "#9B9B9B",
|
||||||
|
"msg-purple": "#E0DDFC",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user