This commit is contained in:
parent
475b67ee02
commit
05a8685504
|
|
@ -13,11 +13,15 @@ import { SidebarItem } from "../all/sidebar-display-item"
|
||||||
import { AssistantRetrievalSelect } from "./assistant-retrieval-select"
|
import { AssistantRetrievalSelect } from "./assistant-retrieval-select"
|
||||||
import { AssistantToolSelect } from "./assistant-tool-select"
|
import { AssistantToolSelect } from "./assistant-tool-select"
|
||||||
|
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
interface AssistantItemProps {
|
interface AssistantItemProps {
|
||||||
assistant: Tables<"assistants">
|
assistant: Tables<"assistants">
|
||||||
}
|
}
|
||||||
|
|
||||||
export const AssistantItem: FC<AssistantItemProps> = ({ assistant }) => {
|
export const AssistantItem: FC<AssistantItemProps> = ({ assistant }) => {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
|
||||||
const { selectedWorkspace, assistantImages } = useContext(ChatbotUIContext)
|
const { selectedWorkspace, assistantImages } = useContext(ChatbotUIContext)
|
||||||
|
|
||||||
const [name, setName] = useState(assistant.name)
|
const [name, setName] = useState(assistant.name)
|
||||||
|
|
@ -167,10 +171,10 @@ export const AssistantItem: FC<AssistantItemProps> = ({ assistant }) => {
|
||||||
}) => (
|
}) => (
|
||||||
<>
|
<>
|
||||||
<div className="space-y-1">
|
<div className="space-y-1">
|
||||||
<Label>Name</Label>
|
<Label>{t("side.name")}</Label>
|
||||||
|
|
||||||
<Input
|
<Input
|
||||||
placeholder="Assistant name..."
|
placeholder={t("side.assistantNamePlaceholder")}
|
||||||
value={name}
|
value={name}
|
||||||
onChange={e => setName(e.target.value)}
|
onChange={e => setName(e.target.value)}
|
||||||
maxLength={ASSISTANT_NAME_MAX}
|
maxLength={ASSISTANT_NAME_MAX}
|
||||||
|
|
@ -178,10 +182,10 @@ export const AssistantItem: FC<AssistantItemProps> = ({ assistant }) => {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-1 pt-2">
|
<div className="space-y-1 pt-2">
|
||||||
<Label>Description</Label>
|
<Label>{t("side.description")}</Label>
|
||||||
|
|
||||||
<Input
|
<Input
|
||||||
placeholder="Assistant description..."
|
placeholder={t("side.assistantDescriptionPlaceholder")}
|
||||||
value={description}
|
value={description}
|
||||||
onChange={e => setDescription(e.target.value)}
|
onChange={e => setDescription(e.target.value)}
|
||||||
maxLength={ASSISTANT_DESCRIPTION_MAX}
|
maxLength={ASSISTANT_DESCRIPTION_MAX}
|
||||||
|
|
@ -189,7 +193,7 @@ export const AssistantItem: FC<AssistantItemProps> = ({ assistant }) => {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-1">
|
<div className="space-y-1">
|
||||||
<Label>Image</Label>
|
<Label>{t("side.image")}</Label>
|
||||||
|
|
||||||
<ImagePicker
|
<ImagePicker
|
||||||
src={imageLink}
|
src={imageLink}
|
||||||
|
|
@ -208,7 +212,7 @@ export const AssistantItem: FC<AssistantItemProps> = ({ assistant }) => {
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className="space-y-1 pt-2">
|
<div className="space-y-1 pt-2">
|
||||||
<Label>Files & Collections</Label>
|
<Label>{t("side.filesAndCollections")}</Label>
|
||||||
|
|
||||||
<AssistantRetrievalSelect
|
<AssistantRetrievalSelect
|
||||||
selectedAssistantRetrievalItems={
|
selectedAssistantRetrievalItems={
|
||||||
|
|
@ -270,7 +274,7 @@ export const AssistantItem: FC<AssistantItemProps> = ({ assistant }) => {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-1">
|
<div className="space-y-1">
|
||||||
<Label>Tools</Label>
|
<Label>{t("side.tools")}</Label>
|
||||||
|
|
||||||
<AssistantToolSelect
|
<AssistantToolSelect
|
||||||
selectedAssistantTools={
|
selectedAssistantTools={
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,8 @@ import {
|
||||||
import { FileIcon } from "lucide-react"
|
import { FileIcon } from "lucide-react"
|
||||||
import { FC, useContext, useEffect, useRef, useState } from "react"
|
import { FC, useContext, useEffect, useRef, useState } from "react"
|
||||||
|
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
interface AssistantRetrievalSelectProps {
|
interface AssistantRetrievalSelectProps {
|
||||||
selectedAssistantRetrievalItems: Tables<"files">[] | Tables<"collections">[]
|
selectedAssistantRetrievalItems: Tables<"files">[] | Tables<"collections">[]
|
||||||
onAssistantRetrievalItemsSelect: (
|
onAssistantRetrievalItemsSelect: (
|
||||||
|
|
@ -26,6 +28,8 @@ export const AssistantRetrievalSelect: FC<AssistantRetrievalSelectProps> = ({
|
||||||
selectedAssistantRetrievalItems,
|
selectedAssistantRetrievalItems,
|
||||||
onAssistantRetrievalItemsSelect
|
onAssistantRetrievalItemsSelect
|
||||||
}) => {
|
}) => {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
|
||||||
const { files, collections } = useContext(ChatbotUIContext)
|
const { files, collections } = useContext(ChatbotUIContext)
|
||||||
|
|
||||||
const inputRef = useRef<HTMLInputElement>(null)
|
const inputRef = useRef<HTMLInputElement>(null)
|
||||||
|
|
@ -67,7 +71,7 @@ export const AssistantRetrievalSelect: FC<AssistantRetrievalSelectProps> = ({
|
||||||
>
|
>
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<div className="ml-2 flex items-center">
|
<div className="ml-2 flex items-center">
|
||||||
{selectedAssistantRetrievalItems.length} files selected
|
{selectedAssistantRetrievalItems.length} {t("side.filesSelected")}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -82,7 +86,7 @@ export const AssistantRetrievalSelect: FC<AssistantRetrievalSelectProps> = ({
|
||||||
>
|
>
|
||||||
<Input
|
<Input
|
||||||
ref={inputRef}
|
ref={inputRef}
|
||||||
placeholder="Search files..."
|
placeholder={t("side.searchFilesPlaceholder")}
|
||||||
value={search}
|
value={search}
|
||||||
onChange={e => setSearch(e.target.value)}
|
onChange={e => setSearch(e.target.value)}
|
||||||
onKeyDown={e => e.stopPropagation()}
|
onKeyDown={e => e.stopPropagation()}
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,8 @@ import {
|
||||||
} from "@tabler/icons-react"
|
} from "@tabler/icons-react"
|
||||||
import { FC, useContext, useEffect, useRef, useState } from "react"
|
import { FC, useContext, useEffect, useRef, useState } from "react"
|
||||||
|
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
interface AssistantToolSelectProps {
|
interface AssistantToolSelectProps {
|
||||||
selectedAssistantTools: Tables<"tools">[]
|
selectedAssistantTools: Tables<"tools">[]
|
||||||
onAssistantToolsSelect: (tool: Tables<"tools">) => void
|
onAssistantToolsSelect: (tool: Tables<"tools">) => void
|
||||||
|
|
@ -23,6 +25,8 @@ export const AssistantToolSelect: FC<AssistantToolSelectProps> = ({
|
||||||
selectedAssistantTools,
|
selectedAssistantTools,
|
||||||
onAssistantToolsSelect
|
onAssistantToolsSelect
|
||||||
}) => {
|
}) => {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
|
||||||
const { tools } = useContext(ChatbotUIContext)
|
const { tools } = useContext(ChatbotUIContext)
|
||||||
|
|
||||||
const inputRef = useRef<HTMLInputElement>(null)
|
const inputRef = useRef<HTMLInputElement>(null)
|
||||||
|
|
@ -64,7 +68,7 @@ export const AssistantToolSelect: FC<AssistantToolSelectProps> = ({
|
||||||
>
|
>
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<div className="ml-2 flex items-center">
|
<div className="ml-2 flex items-center">
|
||||||
{selectedAssistantTools.length} tools selected
|
{selectedAssistantTools.length} {t("side.toolsSelected")}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -79,7 +83,7 @@ export const AssistantToolSelect: FC<AssistantToolSelectProps> = ({
|
||||||
>
|
>
|
||||||
<Input
|
<Input
|
||||||
ref={inputRef}
|
ref={inputRef}
|
||||||
placeholder="Search tools..."
|
placeholder={t("side.searchToolsPlaceholder")}
|
||||||
value={search}
|
value={search}
|
||||||
onChange={e => setSearch(e.target.value)}
|
onChange={e => setSearch(e.target.value)}
|
||||||
onKeyDown={e => e.stopPropagation()}
|
onKeyDown={e => e.stopPropagation()}
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,8 @@ import { CollectionFile } from "@/types"
|
||||||
import { IconChevronDown, IconCircleCheckFilled } from "@tabler/icons-react"
|
import { IconChevronDown, IconCircleCheckFilled } from "@tabler/icons-react"
|
||||||
import { FC, useContext, useEffect, useRef, useState } from "react"
|
import { FC, useContext, useEffect, useRef, useState } from "react"
|
||||||
|
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
interface CollectionFileSelectProps {
|
interface CollectionFileSelectProps {
|
||||||
selectedCollectionFiles: CollectionFile[]
|
selectedCollectionFiles: CollectionFile[]
|
||||||
onCollectionFileSelect: (file: CollectionFile) => void
|
onCollectionFileSelect: (file: CollectionFile) => void
|
||||||
|
|
@ -20,6 +22,8 @@ export const CollectionFileSelect: FC<CollectionFileSelectProps> = ({
|
||||||
selectedCollectionFiles,
|
selectedCollectionFiles,
|
||||||
onCollectionFileSelect
|
onCollectionFileSelect
|
||||||
}) => {
|
}) => {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
|
||||||
const { files } = useContext(ChatbotUIContext)
|
const { files } = useContext(ChatbotUIContext)
|
||||||
|
|
||||||
const inputRef = useRef<HTMLInputElement>(null)
|
const inputRef = useRef<HTMLInputElement>(null)
|
||||||
|
|
@ -61,7 +65,7 @@ export const CollectionFileSelect: FC<CollectionFileSelectProps> = ({
|
||||||
>
|
>
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<div className="ml-2 flex items-center">
|
<div className="ml-2 flex items-center">
|
||||||
{selectedCollectionFiles.length} files selected
|
{selectedCollectionFiles.length} {t("side.filesSelected")}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -76,7 +80,7 @@ export const CollectionFileSelect: FC<CollectionFileSelectProps> = ({
|
||||||
>
|
>
|
||||||
<Input
|
<Input
|
||||||
ref={inputRef}
|
ref={inputRef}
|
||||||
placeholder="Search files..."
|
placeholder={t("side.searchFilesPlaceholder")}
|
||||||
value={search}
|
value={search}
|
||||||
onChange={e => setSearch(e.target.value)}
|
onChange={e => setSearch(e.target.value)}
|
||||||
onKeyDown={e => e.stopPropagation()}
|
onKeyDown={e => e.stopPropagation()}
|
||||||
|
|
|
||||||
|
|
@ -8,11 +8,16 @@ import { FC, useState } from "react"
|
||||||
import { SidebarItem } from "../all/sidebar-display-item"
|
import { SidebarItem } from "../all/sidebar-display-item"
|
||||||
import { CollectionFileSelect } from "./collection-file-select"
|
import { CollectionFileSelect } from "./collection-file-select"
|
||||||
|
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
interface CollectionItemProps {
|
interface CollectionItemProps {
|
||||||
collection: Tables<"collections">
|
collection: Tables<"collections">
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CollectionItem: FC<CollectionItemProps> = ({ collection }) => {
|
export const CollectionItem: FC<CollectionItemProps> = ({ collection }) => {
|
||||||
|
|
||||||
|
const { t } = useTranslation()
|
||||||
|
|
||||||
const [name, setName] = useState(collection.name)
|
const [name, setName] = useState(collection.name)
|
||||||
const [isTyping, setIsTyping] = useState(false)
|
const [isTyping, setIsTyping] = useState(false)
|
||||||
const [description, setDescription] = useState(collection.description)
|
const [description, setDescription] = useState(collection.description)
|
||||||
|
|
@ -59,7 +64,7 @@ export const CollectionItem: FC<CollectionItemProps> = ({ collection }) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="space-y-1">
|
<div className="space-y-1">
|
||||||
<Label>Files</Label>
|
<Label>{t("side.files")}</Label>
|
||||||
|
|
||||||
<CollectionFileSelect
|
<CollectionFileSelect
|
||||||
selectedCollectionFiles={
|
selectedCollectionFiles={
|
||||||
|
|
@ -89,10 +94,10 @@ export const CollectionItem: FC<CollectionItemProps> = ({ collection }) => {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-1">
|
<div className="space-y-1">
|
||||||
<Label>Name</Label>
|
<Label>{t("side.name")}</Label>
|
||||||
|
|
||||||
<Input
|
<Input
|
||||||
placeholder="Collection name..."
|
placeholder={t("side.collectionNamePlaceholder")}
|
||||||
value={name}
|
value={name}
|
||||||
onChange={e => setName(e.target.value)}
|
onChange={e => setName(e.target.value)}
|
||||||
maxLength={COLLECTION_NAME_MAX}
|
maxLength={COLLECTION_NAME_MAX}
|
||||||
|
|
@ -100,10 +105,10 @@ export const CollectionItem: FC<CollectionItemProps> = ({ collection }) => {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-1">
|
<div className="space-y-1">
|
||||||
<Label>Description</Label>
|
<Label>{t("side.description")}</Label>
|
||||||
|
|
||||||
<Input
|
<Input
|
||||||
placeholder="Collection description..."
|
placeholder={t("side.collectionDescriptionPlaceholder")}
|
||||||
value={description}
|
value={description}
|
||||||
onChange={e => setDescription(e.target.value)}
|
onChange={e => setDescription(e.target.value)}
|
||||||
maxLength={COLLECTION_DESCRIPTION_MAX}
|
maxLength={COLLECTION_DESCRIPTION_MAX}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,8 @@ import { CollectionFile } from "@/types"
|
||||||
import { FC, useContext, useState } from "react"
|
import { FC, useContext, useState } from "react"
|
||||||
import { CollectionFileSelect } from "./collection-file-select"
|
import { CollectionFileSelect } from "./collection-file-select"
|
||||||
|
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
interface CreateCollectionProps {
|
interface CreateCollectionProps {
|
||||||
isOpen: boolean
|
isOpen: boolean
|
||||||
onOpenChange: (isOpen: boolean) => void
|
onOpenChange: (isOpen: boolean) => void
|
||||||
|
|
@ -17,6 +19,8 @@ export const CreateCollection: FC<CreateCollectionProps> = ({
|
||||||
isOpen,
|
isOpen,
|
||||||
onOpenChange
|
onOpenChange
|
||||||
}) => {
|
}) => {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
|
||||||
const { profile, selectedWorkspace } = useContext(ChatbotUIContext)
|
const { profile, selectedWorkspace } = useContext(ChatbotUIContext)
|
||||||
|
|
||||||
const [name, setName] = useState("")
|
const [name, setName] = useState("")
|
||||||
|
|
@ -64,7 +68,7 @@ export const CreateCollection: FC<CreateCollectionProps> = ({
|
||||||
renderInputs={() => (
|
renderInputs={() => (
|
||||||
<>
|
<>
|
||||||
<div className="space-y-1">
|
<div className="space-y-1">
|
||||||
<Label>Files</Label>
|
<Label>{t("side.files")}</Label>
|
||||||
|
|
||||||
<CollectionFileSelect
|
<CollectionFileSelect
|
||||||
selectedCollectionFiles={selectedCollectionFiles}
|
selectedCollectionFiles={selectedCollectionFiles}
|
||||||
|
|
@ -73,7 +77,7 @@ export const CreateCollection: FC<CreateCollectionProps> = ({
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-1">
|
<div className="space-y-1">
|
||||||
<Label>Name</Label>
|
<Label>{t("side.name")}</Label>
|
||||||
|
|
||||||
<Input
|
<Input
|
||||||
placeholder="Collection name..."
|
placeholder="Collection name..."
|
||||||
|
|
@ -84,10 +88,10 @@ export const CreateCollection: FC<CreateCollectionProps> = ({
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-1">
|
<div className="space-y-1">
|
||||||
<Label>Description</Label>
|
<Label>{t("side.description")}</Label>
|
||||||
|
|
||||||
<Input
|
<Input
|
||||||
placeholder="Collection description..."
|
placeholder={t("side.collectionDescriptionPlaceholder")}
|
||||||
value={description}
|
value={description}
|
||||||
onChange={e => setDescription(e.target.value)}
|
onChange={e => setDescription(e.target.value)}
|
||||||
maxLength={COLLECTION_DESCRIPTION_MAX}
|
maxLength={COLLECTION_DESCRIPTION_MAX}
|
||||||
|
|
|
||||||
|
|
@ -7,12 +7,16 @@ import { FILE_DESCRIPTION_MAX, FILE_NAME_MAX } from "@/db/limits"
|
||||||
import { TablesInsert } from "@/supabase/types"
|
import { TablesInsert } from "@/supabase/types"
|
||||||
import { FC, useContext, useState } from "react"
|
import { FC, useContext, useState } from "react"
|
||||||
|
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
interface CreateFileProps {
|
interface CreateFileProps {
|
||||||
isOpen: boolean
|
isOpen: boolean
|
||||||
onOpenChange: (isOpen: boolean) => void
|
onOpenChange: (isOpen: boolean) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CreateFile: FC<CreateFileProps> = ({ isOpen, onOpenChange }) => {
|
export const CreateFile: FC<CreateFileProps> = ({ isOpen, onOpenChange }) => {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
|
||||||
const { profile, selectedWorkspace } = useContext(ChatbotUIContext)
|
const { profile, selectedWorkspace } = useContext(ChatbotUIContext)
|
||||||
|
|
||||||
const [name, setName] = useState("")
|
const [name, setName] = useState("")
|
||||||
|
|
@ -56,7 +60,7 @@ export const CreateFile: FC<CreateFileProps> = ({ isOpen, onOpenChange }) => {
|
||||||
renderInputs={() => (
|
renderInputs={() => (
|
||||||
<>
|
<>
|
||||||
<div className="space-y-1">
|
<div className="space-y-1">
|
||||||
<Label>File</Label>
|
<Label>{t("side.file")}</Label>
|
||||||
|
|
||||||
<Input
|
<Input
|
||||||
type="file"
|
type="file"
|
||||||
|
|
@ -66,10 +70,10 @@ export const CreateFile: FC<CreateFileProps> = ({ isOpen, onOpenChange }) => {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-1">
|
<div className="space-y-1">
|
||||||
<Label>Name</Label>
|
<Label>{t("side.name")}</Label>
|
||||||
|
|
||||||
<Input
|
<Input
|
||||||
placeholder="File name..."
|
placeholder={t("side.fileNamePlaceholder")}
|
||||||
value={name}
|
value={name}
|
||||||
onChange={e => setName(e.target.value)}
|
onChange={e => setName(e.target.value)}
|
||||||
maxLength={FILE_NAME_MAX}
|
maxLength={FILE_NAME_MAX}
|
||||||
|
|
@ -77,10 +81,10 @@ export const CreateFile: FC<CreateFileProps> = ({ isOpen, onOpenChange }) => {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-1">
|
<div className="space-y-1">
|
||||||
<Label>Description</Label>
|
<Label>{t("side.description")}</Label>
|
||||||
|
|
||||||
<Input
|
<Input
|
||||||
placeholder="File description..."
|
placeholder={t("side.fileDescriptionPlaceholder")}
|
||||||
value={name}
|
value={name}
|
||||||
onChange={e => setDescription(e.target.value)}
|
onChange={e => setDescription(e.target.value)}
|
||||||
maxLength={FILE_DESCRIPTION_MAX}
|
maxLength={FILE_DESCRIPTION_MAX}
|
||||||
|
|
|
||||||
|
|
@ -6,12 +6,14 @@ import { getFileFromStorage } from "@/db/storage/files"
|
||||||
import { Tables } from "@/supabase/types"
|
import { Tables } from "@/supabase/types"
|
||||||
import { FC, useState } from "react"
|
import { FC, useState } from "react"
|
||||||
import { SidebarItem } from "../all/sidebar-display-item"
|
import { SidebarItem } from "../all/sidebar-display-item"
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
interface FileItemProps {
|
interface FileItemProps {
|
||||||
file: Tables<"files">
|
file: Tables<"files">
|
||||||
}
|
}
|
||||||
|
|
||||||
export const FileItem: FC<FileItemProps> = ({ file }) => {
|
export const FileItem: FC<FileItemProps> = ({ file }) => {
|
||||||
|
const { t } = useTranslation()
|
||||||
const [name, setName] = useState(file.name)
|
const [name, setName] = useState(file.name)
|
||||||
const [isTyping, setIsTyping] = useState(false)
|
const [isTyping, setIsTyping] = useState(false)
|
||||||
const [description, setDescription] = useState(file.description)
|
const [description, setDescription] = useState(file.description)
|
||||||
|
|
@ -34,7 +36,7 @@ export const FileItem: FC<FileItemProps> = ({ file }) => {
|
||||||
className="cursor-pointer underline hover:opacity-50"
|
className="cursor-pointer underline hover:opacity-50"
|
||||||
onClick={getLinkAndView}
|
onClick={getLinkAndView}
|
||||||
>
|
>
|
||||||
View {file.name}
|
{t("side.view")} {file.name}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex flex-col justify-between">
|
<div className="flex flex-col justify-between">
|
||||||
|
|
@ -46,10 +48,10 @@ export const FileItem: FC<FileItemProps> = ({ file }) => {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-1">
|
<div className="space-y-1">
|
||||||
<Label>Name</Label>
|
<Label>{t("side.name")}</Label>
|
||||||
|
|
||||||
<Input
|
<Input
|
||||||
placeholder="File name..."
|
placeholder={t("side.fileNamePlaceholder")}
|
||||||
value={name}
|
value={name}
|
||||||
onChange={e => setName(e.target.value)}
|
onChange={e => setName(e.target.value)}
|
||||||
maxLength={FILE_NAME_MAX}
|
maxLength={FILE_NAME_MAX}
|
||||||
|
|
@ -57,10 +59,10 @@ export const FileItem: FC<FileItemProps> = ({ file }) => {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-1">
|
<div className="space-y-1">
|
||||||
<Label>Description</Label>
|
<Label>{t("side.description")}</Label>
|
||||||
|
|
||||||
<Input
|
<Input
|
||||||
placeholder="File description..."
|
placeholder={t("side.fileDescriptionPlaceholder")}
|
||||||
value={description}
|
value={description}
|
||||||
onChange={e => setDescription(e.target.value)}
|
onChange={e => setDescription(e.target.value)}
|
||||||
maxLength={FILE_DESCRIPTION_MAX}
|
maxLength={FILE_DESCRIPTION_MAX}
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ import { ContentType } from "@/types"
|
||||||
import { IconTrash } from "@tabler/icons-react"
|
import { IconTrash } from "@tabler/icons-react"
|
||||||
import { FC, useContext, useRef, useState } from "react"
|
import { FC, useContext, useRef, useState } from "react"
|
||||||
import { toast } from "sonner"
|
import { toast } from "sonner"
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
interface DeleteFolderProps {
|
interface DeleteFolderProps {
|
||||||
folder: Tables<"folders">
|
folder: Tables<"folders">
|
||||||
|
|
@ -26,6 +27,7 @@ export const DeleteFolder: FC<DeleteFolderProps> = ({
|
||||||
folder,
|
folder,
|
||||||
contentType
|
contentType
|
||||||
}) => {
|
}) => {
|
||||||
|
const { t } = useTranslation()
|
||||||
const {
|
const {
|
||||||
setChats,
|
setChats,
|
||||||
setFolders,
|
setFolders,
|
||||||
|
|
@ -107,16 +109,16 @@ export const DeleteFolder: FC<DeleteFolderProps> = ({
|
||||||
|
|
||||||
<DialogContent className="min-w-[550px]">
|
<DialogContent className="min-w-[550px]">
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle>Delete {folder.name}</DialogTitle>
|
<DialogTitle>{t("side.delete")} {folder.name}</DialogTitle>
|
||||||
|
|
||||||
<DialogDescription>
|
<DialogDescription>
|
||||||
Are you sure you want to delete this folder?
|
{t("side.confirmDeleteFolder")}
|
||||||
</DialogDescription>
|
</DialogDescription>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
|
|
||||||
<DialogFooter>
|
<DialogFooter>
|
||||||
<Button variant="ghost" onClick={() => setShowFolderDialog(false)}>
|
<Button variant="ghost" onClick={() => setShowFolderDialog(false)}>
|
||||||
Cancel
|
{t("side.cancel")}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
|
|
@ -124,7 +126,7 @@ export const DeleteFolder: FC<DeleteFolderProps> = ({
|
||||||
variant="destructive"
|
variant="destructive"
|
||||||
onClick={handleDeleteFolderAndItems}
|
onClick={handleDeleteFolderAndItems}
|
||||||
>
|
>
|
||||||
Delete Folder & Included Items
|
{t("side.deleteFolderWithContents")}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
|
|
@ -132,7 +134,7 @@ export const DeleteFolder: FC<DeleteFolderProps> = ({
|
||||||
variant="destructive"
|
variant="destructive"
|
||||||
onClick={handleDeleteFolderOnly}
|
onClick={handleDeleteFolderOnly}
|
||||||
>
|
>
|
||||||
Delete Folder Only
|
{t("side.deleteFolderOnly")}
|
||||||
</Button>
|
</Button>
|
||||||
</DialogFooter>
|
</DialogFooter>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
|
|
|
||||||
|
|
@ -14,12 +14,14 @@ import { updateFolder } from "@/db/folders"
|
||||||
import { Tables } from "@/supabase/types"
|
import { Tables } from "@/supabase/types"
|
||||||
import { IconEdit } from "@tabler/icons-react"
|
import { IconEdit } from "@tabler/icons-react"
|
||||||
import { FC, useContext, useRef, useState } from "react"
|
import { FC, useContext, useRef, useState } from "react"
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
interface UpdateFolderProps {
|
interface UpdateFolderProps {
|
||||||
folder: Tables<"folders">
|
folder: Tables<"folders">
|
||||||
}
|
}
|
||||||
|
|
||||||
export const UpdateFolder: FC<UpdateFolderProps> = ({ folder }) => {
|
export const UpdateFolder: FC<UpdateFolderProps> = ({ folder }) => {
|
||||||
|
const { t } = useTranslation()
|
||||||
const { setFolders } = useContext(ChatbotUIContext)
|
const { setFolders } = useContext(ChatbotUIContext)
|
||||||
|
|
||||||
const buttonRef = useRef<HTMLButtonElement>(null)
|
const buttonRef = useRef<HTMLButtonElement>(null)
|
||||||
|
|
@ -52,22 +54,22 @@ export const UpdateFolder: FC<UpdateFolderProps> = ({ folder }) => {
|
||||||
|
|
||||||
<DialogContent onKeyDown={handleKeyDown}>
|
<DialogContent onKeyDown={handleKeyDown}>
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle>Edit Folder</DialogTitle>
|
<DialogTitle>{t("side.editFolder")}</DialogTitle>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
|
|
||||||
<div className="space-y-1">
|
<div className="space-y-1">
|
||||||
<Label>Name</Label>
|
<Label>{t("side.name")}</Label>
|
||||||
|
|
||||||
<Input value={name} onChange={e => setName(e.target.value)} />
|
<Input value={name} onChange={e => setName(e.target.value)} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<DialogFooter>
|
<DialogFooter>
|
||||||
<Button variant="ghost" onClick={() => setShowFolderDialog(false)}>
|
<Button variant="ghost" onClick={() => setShowFolderDialog(false)}>
|
||||||
Cancel
|
{t("side.cancel")}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Button ref={buttonRef} onClick={handleUpdateFolder}>
|
<Button ref={buttonRef} onClick={handleUpdateFolder}>
|
||||||
Save
|
{t("side.save")}
|
||||||
</Button>
|
</Button>
|
||||||
</DialogFooter>
|
</DialogFooter>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import { ChatbotUIContext } from "@/context/context"
|
||||||
import { MODEL_NAME_MAX } from "@/db/limits"
|
import { MODEL_NAME_MAX } from "@/db/limits"
|
||||||
import { TablesInsert } from "@/supabase/types"
|
import { TablesInsert } from "@/supabase/types"
|
||||||
import { FC, useContext, useState } from "react"
|
import { FC, useContext, useState } from "react"
|
||||||
|
import { useTranslation, Trans } from 'react-i18next'
|
||||||
|
|
||||||
interface CreateModelProps {
|
interface CreateModelProps {
|
||||||
isOpen: boolean
|
isOpen: boolean
|
||||||
|
|
@ -12,6 +13,7 @@ interface CreateModelProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CreateModel: FC<CreateModelProps> = ({ isOpen, onOpenChange }) => {
|
export const CreateModel: FC<CreateModelProps> = ({ isOpen, onOpenChange }) => {
|
||||||
|
const { t } = useTranslation()
|
||||||
const { profile, selectedWorkspace } = useContext(ChatbotUIContext)
|
const { profile, selectedWorkspace } = useContext(ChatbotUIContext)
|
||||||
|
|
||||||
const [isTyping, setIsTyping] = useState(false)
|
const [isTyping, setIsTyping] = useState(false)
|
||||||
|
|
@ -45,19 +47,20 @@ export const CreateModel: FC<CreateModelProps> = ({ isOpen, onOpenChange }) => {
|
||||||
renderInputs={() => (
|
renderInputs={() => (
|
||||||
<>
|
<>
|
||||||
<div className="space-y-1.5 text-sm">
|
<div className="space-y-1.5 text-sm">
|
||||||
<div>Create a custom model.</div>
|
<div>{t("side.createCustomModel")}</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
Your API <span className="font-bold">*must*</span> be compatible
|
{/* Your API <span className="font-bold">*must*</span> be compatible
|
||||||
with the OpenAI SDK.
|
with the OpenAI SDK. */}
|
||||||
|
<Trans i18nKey="side.apiCompatibilityWarning" components={{ strong: <span className="font-bold" /> }} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-1">
|
<div className="space-y-1">
|
||||||
<Label>Name</Label>
|
<Label>{t("side.name")}</Label>
|
||||||
|
|
||||||
<Input
|
<Input
|
||||||
placeholder="Model name..."
|
placeholder={t("side.modelNamePlaceholder")}
|
||||||
value={name}
|
value={name}
|
||||||
onChange={e => setName(e.target.value)}
|
onChange={e => setName(e.target.value)}
|
||||||
maxLength={MODEL_NAME_MAX}
|
maxLength={MODEL_NAME_MAX}
|
||||||
|
|
@ -65,42 +68,43 @@ export const CreateModel: FC<CreateModelProps> = ({ isOpen, onOpenChange }) => {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-1">
|
<div className="space-y-1">
|
||||||
<Label>Model ID</Label>
|
<Label>{t("side.modelId")}</Label>
|
||||||
|
|
||||||
<Input
|
<Input
|
||||||
placeholder="Model ID..."
|
placeholder={t("side.modelIdPlaceholder")}
|
||||||
value={modelId}
|
value={modelId}
|
||||||
onChange={e => setModelId(e.target.value)}
|
onChange={e => setModelId(e.target.value)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-1">
|
<div className="space-y-1">
|
||||||
<Label>Base URL</Label>
|
<Label>{t("side.baseUrl")}</Label>
|
||||||
|
|
||||||
<Input
|
<Input
|
||||||
placeholder="Base URL..."
|
placeholder={t("side.baseUrlPlaceholder")}
|
||||||
value={baseUrl}
|
value={baseUrl}
|
||||||
onChange={e => setBaseUrl(e.target.value)}
|
onChange={e => setBaseUrl(e.target.value)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className="pt-1 text-xs italic">
|
<div className="pt-1 text-xs italic">
|
||||||
Your API must be compatible with the OpenAI SDK.
|
{t("side.apiCompatibilityNotice")}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-1">
|
<div className="space-y-1">
|
||||||
<Label>API Key</Label>
|
<Label>{t("side.apiKey")}</Label>
|
||||||
|
|
||||||
<Input
|
<Input
|
||||||
type="password"
|
type="password"
|
||||||
placeholder="API Key..."
|
placeholder={t("side.apiKeyPlaceholder")}
|
||||||
value={apiKey}
|
value={apiKey}
|
||||||
onChange={e => setApiKey(e.target.value)}
|
onChange={e => setApiKey(e.target.value)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-1">
|
<div className="space-y-1">
|
||||||
<Label>Max Context Length</Label>
|
<Label>{t("side.maxContextLength")}</Label>
|
||||||
|
|
||||||
<Input
|
<Input
|
||||||
type="number"
|
type="number"
|
||||||
|
|
|
||||||
|
|
@ -166,7 +166,33 @@
|
||||||
"editChat": "Edit Chat",
|
"editChat": "Edit Chat",
|
||||||
"confirmDelete": "Are you sure you want to delete?",
|
"confirmDelete": "Are you sure you want to delete?",
|
||||||
"edit": "Edit",
|
"edit": "Edit",
|
||||||
"assignedWorkspaces": "Assigned Workspaces"
|
"assignedWorkspaces": "Assigned Workspaces",
|
||||||
|
"searchFilesPlaceholder": "Search files...",
|
||||||
|
"filesSelected": "files selected",
|
||||||
|
"toolsSelected": "tools selected",
|
||||||
|
"searchToolsPlaceholder": "Search tools...",
|
||||||
|
"files": "Files",
|
||||||
|
"file": "File",
|
||||||
|
"collectionDescriptionPlaceholder": "Collection description...",
|
||||||
|
"collectionNamePlaceholder": "Collection name...",
|
||||||
|
"fileNamePlaceholder": "File name...",
|
||||||
|
"fileDescriptionPlaceholder": "File description...",
|
||||||
|
"view": "View",
|
||||||
|
"confirmDeleteFolder": "Are you sure you want to delete this folder?",
|
||||||
|
"deleteFolderWithContents": "Delete Folder & Included Items",
|
||||||
|
"deleteFolderOnly": "Delete Folder Only",
|
||||||
|
"editFolder": "Edit Folder",
|
||||||
|
"createCustomModel": "Create a custom model.",
|
||||||
|
"apiCompatibilityWarning": "Your API <strong>*must*</strong> be compatible with the OpenAI SDK.",
|
||||||
|
"apiCompatibilityNotice": "Your API must be compatible with the OpenAI SDK.",
|
||||||
|
"modelNamePlaceholder": "Model name...",
|
||||||
|
"modelId": "Model ID",
|
||||||
|
"modelIdPlaceholder": "Model ID...",
|
||||||
|
"baseUrl": "Base URL",
|
||||||
|
"baseUrlPlaceholder": "Base URL...",
|
||||||
|
"apiKey": "API Key",
|
||||||
|
"apiKeyPlaceholder": "API Key...",
|
||||||
|
"maxContextLength": "Max Context Length"
|
||||||
},
|
},
|
||||||
|
|
||||||
"contentType": {
|
"contentType": {
|
||||||
|
|
|
||||||
|
|
@ -165,7 +165,33 @@
|
||||||
"editChat": "チャットを編集",
|
"editChat": "チャットを編集",
|
||||||
"confirmDelete": "本当に削除しますか?",
|
"confirmDelete": "本当に削除しますか?",
|
||||||
"edit": "編集",
|
"edit": "編集",
|
||||||
"assignedWorkspaces": "割り当てられたワークスペース"
|
"assignedWorkspaces": "割り当てられたワークスペース",
|
||||||
|
"searchFilesPlaceholder": "ファイルを検索...",
|
||||||
|
"filesSelected": "件のファイルが選択されました",
|
||||||
|
"toolsSelected": "件のツールが選択されました",
|
||||||
|
"searchToolsPlaceholder": "ツールを検索...",
|
||||||
|
"files": "ファイル",
|
||||||
|
"file": "ファイル",
|
||||||
|
"collectionDescriptionPlaceholder": "コレクションの説明...",
|
||||||
|
"collectionNamePlaceholder": "コレクション名...",
|
||||||
|
"fileNamePlaceholder": "ファイル名...",
|
||||||
|
"fileDescriptionPlaceholder": "ファイルの説明...",
|
||||||
|
"view": "表示",
|
||||||
|
"confirmDeleteFolder": "このフォルダーを削除してもよろしいですか?",
|
||||||
|
"deleteFolderWithContents": "フォルダーと含まれる項目を削除",
|
||||||
|
"deleteFolderOnly": "フォルダーのみ削除",
|
||||||
|
"editFolder": "フォルダーを編集",
|
||||||
|
"createCustomModel": "カスタムモデルを作成します。",
|
||||||
|
"apiCompatibilityWarning": "あなたの API は <strong>*完全に*</strong> OpenAI SDK と互換である必要があります。",
|
||||||
|
"apiCompatibilityNotice": "あなたの API は OpenAI SDK と互換である必要があります。",
|
||||||
|
"modelNamePlaceholder": "モデル名...",
|
||||||
|
"modelId": "モデル ID",
|
||||||
|
"modelIdPlaceholder": "モデル ID...",
|
||||||
|
"baseUrl": "ベース URL",
|
||||||
|
"baseUrlPlaceholder": "ベース URL...",
|
||||||
|
"apiKey": "API キー",
|
||||||
|
"apiKeyPlaceholder": "API キー...",
|
||||||
|
"maxContextLength": "最大コンテキスト長"
|
||||||
},
|
},
|
||||||
|
|
||||||
"contentType": {
|
"contentType": {
|
||||||
|
|
|
||||||
|
|
@ -165,7 +165,33 @@
|
||||||
"editChat": "编辑对话",
|
"editChat": "编辑对话",
|
||||||
"confirmDelete": "你确定要删除吗?",
|
"confirmDelete": "你确定要删除吗?",
|
||||||
"edit": "编辑",
|
"edit": "编辑",
|
||||||
"assignedWorkspaces": "已分配的工作区"
|
"assignedWorkspaces": "已分配的工作区",
|
||||||
|
"searchFilesPlaceholder": "搜索文件...",
|
||||||
|
"filesSelected": "个文件已选择",
|
||||||
|
"toolsSelected": "个工具已选择",
|
||||||
|
"searchToolsPlaceholder": "搜索工具...",
|
||||||
|
"files": "文件",
|
||||||
|
"file": "文件",
|
||||||
|
"collectionDescriptionPlaceholder": "集合描述...",
|
||||||
|
"collectionNamePlaceholder": "集合名称...",
|
||||||
|
"fileNamePlaceholder": "文件名称...",
|
||||||
|
"fileDescriptionPlaceholder": "文件描述...",
|
||||||
|
"view": "查看",
|
||||||
|
"confirmDeleteFolder": "你确定要删除这个文件夹吗?",
|
||||||
|
"deleteFolderWithContents": "删除文件夹及其内容",
|
||||||
|
"deleteFolderOnly": "仅删除文件夹",
|
||||||
|
"editFolder": "编辑文件夹",
|
||||||
|
"createCustomModel": "创建自定义模型。",
|
||||||
|
"apiCompatibilityWarning": "您的 API <strong>*必须*</strong> 与 OpenAI SDK 兼容。",
|
||||||
|
"apiCompatibilityNotice": "您的 API 必须与 OpenAI SDK 兼容。",
|
||||||
|
"modelNamePlaceholder": "模型名称...",
|
||||||
|
"modelId": "模型 ID",
|
||||||
|
"modelIdPlaceholder": "模型 ID...",
|
||||||
|
"baseUrl": "基础地址",
|
||||||
|
"baseUrlPlaceholder": "基础地址...",
|
||||||
|
"apiKey": "API 密钥",
|
||||||
|
"apiKeyPlaceholder": "API 密钥...",
|
||||||
|
"maxContextLength": "最大上下文长度"
|
||||||
},
|
},
|
||||||
|
|
||||||
"contentType": {
|
"contentType": {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue