mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-05-17 18:35:19 +02:00
feat: improve chat renaming functionality with dialog support in sidebar components
This commit is contained in:
parent
f3652ad7cf
commit
f0d170a595
12 changed files with 213 additions and 23 deletions
|
|
@ -3,12 +3,12 @@
|
||||||
import { useSetAtom } from "jotai";
|
import { useSetAtom } from "jotai";
|
||||||
import {
|
import {
|
||||||
CircleAlert,
|
CircleAlert,
|
||||||
FilePlus2,
|
|
||||||
FileType,
|
FileType,
|
||||||
ListFilter,
|
ListFilter,
|
||||||
Search,
|
Search,
|
||||||
SlidersHorizontal,
|
SlidersHorizontal,
|
||||||
Trash,
|
Trash,
|
||||||
|
Upload,
|
||||||
X,
|
X,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import { motion } from "motion/react";
|
import { motion } from "motion/react";
|
||||||
|
|
@ -96,7 +96,7 @@ export function DocumentsFilters({
|
||||||
size="sm"
|
size="sm"
|
||||||
className="h-9 gap-2 bg-white text-gray-700 border-white hover:bg-gray-50 dark:bg-white dark:text-gray-800 dark:hover:bg-gray-100"
|
className="h-9 gap-2 bg-white text-gray-700 border-white hover:bg-gray-50 dark:bg-white dark:text-gray-800 dark:hover:bg-gray-100"
|
||||||
>
|
>
|
||||||
<FilePlus2 size={16} />
|
<Upload size={16} />
|
||||||
<span>Upload documents</span>
|
<span>Upload documents</span>
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
|
|
|
||||||
|
|
@ -129,9 +129,6 @@ const DocumentUploadPopupContent: FC<{
|
||||||
<div className="sticky top-0 z-20 bg-muted px-4 sm:px-12 pt-4 sm:pt-10 pb-2 sm:pb-0">
|
<div className="sticky top-0 z-20 bg-muted px-4 sm:px-12 pt-4 sm:pt-10 pb-2 sm:pb-0">
|
||||||
{/* Upload header */}
|
{/* Upload header */}
|
||||||
<div className="flex items-center gap-2 sm:gap-4 mb-2 sm:mb-6">
|
<div className="flex items-center gap-2 sm:gap-4 mb-2 sm:mb-6">
|
||||||
<div className="flex h-9 w-9 sm:h-14 sm:w-14 items-center justify-center rounded-lg sm:rounded-xl bg-primary/10 border border-primary/20 flex-shrink-0">
|
|
||||||
<Upload className="size-4 sm:size-7 text-primary" />
|
|
||||||
</div>
|
|
||||||
<div className="flex-1 min-w-0 pr-8 sm:pr-0">
|
<div className="flex-1 min-w-0 pr-8 sm:pr-0">
|
||||||
<h2 className="text-base sm:text-2xl font-semibold tracking-tight">
|
<h2 className="text-base sm:text-2xl font-semibold tracking-tight">
|
||||||
Upload Documents
|
Upload Documents
|
||||||
|
|
|
||||||
|
|
@ -703,7 +703,6 @@ export function LayoutDataProvider({
|
||||||
<DialogContent className="sm:max-w-md">
|
<DialogContent className="sm:max-w-md">
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle className="flex items-center gap-2">
|
<DialogTitle className="flex items-center gap-2">
|
||||||
<PencilIcon className="h-5 w-5" />
|
|
||||||
<span>{tSidebar("rename_chat") || "Rename Chat"}</span>
|
<span>{tSidebar("rename_chat") || "Rename Chat"}</span>
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
<DialogDescription>
|
<DialogDescription>
|
||||||
|
|
@ -736,7 +735,7 @@ export function LayoutDataProvider({
|
||||||
{isRenamingChat ? (
|
{isRenamingChat ? (
|
||||||
<>
|
<>
|
||||||
<span className="h-4 w-4 animate-spin rounded-full border-2 border-current border-t-transparent" />
|
<span className="h-4 w-4 animate-spin rounded-full border-2 border-current border-t-transparent" />
|
||||||
{tSidebar("renaming") || "Renaming..."}
|
{tSidebar("renaming") || "Renaming"}
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import {
|
||||||
ArchiveIcon,
|
ArchiveIcon,
|
||||||
MessageCircleMore,
|
MessageCircleMore,
|
||||||
MoreHorizontal,
|
MoreHorizontal,
|
||||||
|
PenLine,
|
||||||
RotateCcwIcon,
|
RotateCcwIcon,
|
||||||
Search,
|
Search,
|
||||||
Trash2,
|
Trash2,
|
||||||
|
|
@ -17,6 +18,14 @@ import { useTranslations } from "next-intl";
|
||||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
|
import {
|
||||||
|
Dialog,
|
||||||
|
DialogContent,
|
||||||
|
DialogDescription,
|
||||||
|
DialogFooter,
|
||||||
|
DialogHeader,
|
||||||
|
DialogTitle,
|
||||||
|
} from "@/components/ui/dialog";
|
||||||
import {
|
import {
|
||||||
DropdownMenu,
|
DropdownMenu,
|
||||||
DropdownMenuContent,
|
DropdownMenuContent,
|
||||||
|
|
@ -69,6 +78,10 @@ export function AllPrivateChatsSidebar({
|
||||||
const [searchQuery, setSearchQuery] = useState("");
|
const [searchQuery, setSearchQuery] = useState("");
|
||||||
const [showArchived, setShowArchived] = useState(false);
|
const [showArchived, setShowArchived] = useState(false);
|
||||||
const [openDropdownId, setOpenDropdownId] = useState<number | null>(null);
|
const [openDropdownId, setOpenDropdownId] = useState<number | null>(null);
|
||||||
|
const [showRenameDialog, setShowRenameDialog] = useState(false);
|
||||||
|
const [renamingThread, setRenamingThread] = useState<{ id: number; title: string } | null>(null);
|
||||||
|
const [newTitle, setNewTitle] = useState("");
|
||||||
|
const [isRenaming, setIsRenaming] = useState(false);
|
||||||
const debouncedSearchQuery = useDebouncedValue(searchQuery, 300);
|
const debouncedSearchQuery = useDebouncedValue(searchQuery, 300);
|
||||||
|
|
||||||
const isSearchMode = !!debouncedSearchQuery.trim();
|
const isSearchMode = !!debouncedSearchQuery.trim();
|
||||||
|
|
@ -187,6 +200,35 @@ export function AllPrivateChatsSidebar({
|
||||||
[queryClient, searchSpaceId, t]
|
[queryClient, searchSpaceId, t]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const handleStartRename = useCallback((threadId: number, title: string) => {
|
||||||
|
setRenamingThread({ id: threadId, title });
|
||||||
|
setNewTitle(title);
|
||||||
|
setShowRenameDialog(true);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleConfirmRename = useCallback(async () => {
|
||||||
|
if (!renamingThread || !newTitle.trim()) return;
|
||||||
|
setIsRenaming(true);
|
||||||
|
try {
|
||||||
|
await updateThread(renamingThread.id, { title: newTitle.trim() });
|
||||||
|
toast.success(t("chat_renamed") || "Chat renamed");
|
||||||
|
queryClient.invalidateQueries({ queryKey: ["all-threads", searchSpaceId] });
|
||||||
|
queryClient.invalidateQueries({ queryKey: ["search-threads", searchSpaceId] });
|
||||||
|
queryClient.invalidateQueries({ queryKey: ["threads", searchSpaceId] });
|
||||||
|
queryClient.invalidateQueries({
|
||||||
|
queryKey: ["threads", searchSpaceId, "detail", String(renamingThread.id)],
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error renaming thread:", error);
|
||||||
|
toast.error(t("error_renaming_chat") || "Failed to rename chat");
|
||||||
|
} finally {
|
||||||
|
setIsRenaming(false);
|
||||||
|
setShowRenameDialog(false);
|
||||||
|
setRenamingThread(null);
|
||||||
|
setNewTitle("");
|
||||||
|
}
|
||||||
|
}, [renamingThread, newTitle, queryClient, searchSpaceId, t]);
|
||||||
|
|
||||||
const handleClearSearch = useCallback(() => {
|
const handleClearSearch = useCallback(() => {
|
||||||
setSearchQuery("");
|
setSearchQuery("");
|
||||||
}, []);
|
}, []);
|
||||||
|
|
@ -355,11 +397,19 @@ export function AllPrivateChatsSidebar({
|
||||||
<span className="sr-only">{t("more_options") || "More options"}</span>
|
<span className="sr-only">{t("more_options") || "More options"}</span>
|
||||||
</Button>
|
</Button>
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent align="end" className="w-40 z-80">
|
<DropdownMenuContent align="end" className="w-40 z-80">
|
||||||
|
{!thread.archived && (
|
||||||
<DropdownMenuItem
|
<DropdownMenuItem
|
||||||
onClick={() => handleToggleArchive(thread.id, thread.archived)}
|
onClick={() => handleStartRename(thread.id, thread.title || "New Chat")}
|
||||||
disabled={isArchiving}
|
|
||||||
>
|
>
|
||||||
|
<PenLine className="mr-2 h-4 w-4" />
|
||||||
|
<span>{t("rename") || "Rename"}</span>
|
||||||
|
</DropdownMenuItem>
|
||||||
|
)}
|
||||||
|
<DropdownMenuItem
|
||||||
|
onClick={() => handleToggleArchive(thread.id, thread.archived)}
|
||||||
|
disabled={isArchiving}
|
||||||
|
>
|
||||||
{thread.archived ? (
|
{thread.archived ? (
|
||||||
<>
|
<>
|
||||||
<RotateCcwIcon className="mr-2 h-4 w-4" />
|
<RotateCcwIcon className="mr-2 h-4 w-4" />
|
||||||
|
|
@ -412,6 +462,51 @@ export function AllPrivateChatsSidebar({
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
<Dialog open={showRenameDialog} onOpenChange={setShowRenameDialog}>
|
||||||
|
<DialogContent className="sm:max-w-md">
|
||||||
|
<DialogHeader>
|
||||||
|
<DialogTitle className="flex items-center gap-2">
|
||||||
|
<span>{t("rename_chat") || "Rename Chat"}</span>
|
||||||
|
</DialogTitle>
|
||||||
|
<DialogDescription>
|
||||||
|
{t("rename_chat_description") || "Enter a new name for this conversation."}
|
||||||
|
</DialogDescription>
|
||||||
|
</DialogHeader>
|
||||||
|
<Input
|
||||||
|
value={newTitle}
|
||||||
|
onChange={(e) => setNewTitle(e.target.value)}
|
||||||
|
placeholder={t("chat_title_placeholder") || "Chat title"}
|
||||||
|
onKeyDown={(e) => {
|
||||||
|
if (e.key === "Enter" && !isRenaming && newTitle.trim()) {
|
||||||
|
handleConfirmRename();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<DialogFooter className="flex gap-2 sm:justify-end">
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
onClick={() => setShowRenameDialog(false)}
|
||||||
|
disabled={isRenaming}
|
||||||
|
>
|
||||||
|
{t("cancel")}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
onClick={handleConfirmRename}
|
||||||
|
disabled={isRenaming || !newTitle.trim()}
|
||||||
|
className="gap-2"
|
||||||
|
>
|
||||||
|
{isRenaming ? (
|
||||||
|
<>
|
||||||
|
<Spinner size="xs" />
|
||||||
|
<span>{t("renaming") || "Renaming"}</span>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<span>{t("rename") || "Rename"}</span>
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
</DialogFooter>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
</SidebarSlideOutPanel>
|
</SidebarSlideOutPanel>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import {
|
||||||
ArchiveIcon,
|
ArchiveIcon,
|
||||||
MessageCircleMore,
|
MessageCircleMore,
|
||||||
MoreHorizontal,
|
MoreHorizontal,
|
||||||
|
PenLine,
|
||||||
RotateCcwIcon,
|
RotateCcwIcon,
|
||||||
Search,
|
Search,
|
||||||
Trash2,
|
Trash2,
|
||||||
|
|
@ -17,6 +18,14 @@ import { useTranslations } from "next-intl";
|
||||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
|
import {
|
||||||
|
Dialog,
|
||||||
|
DialogContent,
|
||||||
|
DialogDescription,
|
||||||
|
DialogFooter,
|
||||||
|
DialogHeader,
|
||||||
|
DialogTitle,
|
||||||
|
} from "@/components/ui/dialog";
|
||||||
import {
|
import {
|
||||||
DropdownMenu,
|
DropdownMenu,
|
||||||
DropdownMenuContent,
|
DropdownMenuContent,
|
||||||
|
|
@ -69,6 +78,10 @@ export function AllSharedChatsSidebar({
|
||||||
const [searchQuery, setSearchQuery] = useState("");
|
const [searchQuery, setSearchQuery] = useState("");
|
||||||
const [showArchived, setShowArchived] = useState(false);
|
const [showArchived, setShowArchived] = useState(false);
|
||||||
const [openDropdownId, setOpenDropdownId] = useState<number | null>(null);
|
const [openDropdownId, setOpenDropdownId] = useState<number | null>(null);
|
||||||
|
const [showRenameDialog, setShowRenameDialog] = useState(false);
|
||||||
|
const [renamingThread, setRenamingThread] = useState<{ id: number; title: string } | null>(null);
|
||||||
|
const [newTitle, setNewTitle] = useState("");
|
||||||
|
const [isRenaming, setIsRenaming] = useState(false);
|
||||||
const debouncedSearchQuery = useDebouncedValue(searchQuery, 300);
|
const debouncedSearchQuery = useDebouncedValue(searchQuery, 300);
|
||||||
|
|
||||||
const isSearchMode = !!debouncedSearchQuery.trim();
|
const isSearchMode = !!debouncedSearchQuery.trim();
|
||||||
|
|
@ -187,6 +200,35 @@ export function AllSharedChatsSidebar({
|
||||||
[queryClient, searchSpaceId, t]
|
[queryClient, searchSpaceId, t]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const handleStartRename = useCallback((threadId: number, title: string) => {
|
||||||
|
setRenamingThread({ id: threadId, title });
|
||||||
|
setNewTitle(title);
|
||||||
|
setShowRenameDialog(true);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleConfirmRename = useCallback(async () => {
|
||||||
|
if (!renamingThread || !newTitle.trim()) return;
|
||||||
|
setIsRenaming(true);
|
||||||
|
try {
|
||||||
|
await updateThread(renamingThread.id, { title: newTitle.trim() });
|
||||||
|
toast.success(t("chat_renamed") || "Chat renamed");
|
||||||
|
queryClient.invalidateQueries({ queryKey: ["all-threads", searchSpaceId] });
|
||||||
|
queryClient.invalidateQueries({ queryKey: ["search-threads", searchSpaceId] });
|
||||||
|
queryClient.invalidateQueries({ queryKey: ["threads", searchSpaceId] });
|
||||||
|
queryClient.invalidateQueries({
|
||||||
|
queryKey: ["threads", searchSpaceId, "detail", String(renamingThread.id)],
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error renaming thread:", error);
|
||||||
|
toast.error(t("error_renaming_chat") || "Failed to rename chat");
|
||||||
|
} finally {
|
||||||
|
setIsRenaming(false);
|
||||||
|
setShowRenameDialog(false);
|
||||||
|
setRenamingThread(null);
|
||||||
|
setNewTitle("");
|
||||||
|
}
|
||||||
|
}, [renamingThread, newTitle, queryClient, searchSpaceId, t]);
|
||||||
|
|
||||||
const handleClearSearch = useCallback(() => {
|
const handleClearSearch = useCallback(() => {
|
||||||
setSearchQuery("");
|
setSearchQuery("");
|
||||||
}, []);
|
}, []);
|
||||||
|
|
@ -355,12 +397,20 @@ export function AllSharedChatsSidebar({
|
||||||
<span className="sr-only">{t("more_options") || "More options"}</span>
|
<span className="sr-only">{t("more_options") || "More options"}</span>
|
||||||
</Button>
|
</Button>
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent align="end" className="w-40 z-80">
|
<DropdownMenuContent align="end" className="w-40 z-80">
|
||||||
|
{!thread.archived && (
|
||||||
<DropdownMenuItem
|
<DropdownMenuItem
|
||||||
onClick={() => handleToggleArchive(thread.id, thread.archived)}
|
onClick={() => handleStartRename(thread.id, thread.title || "New Chat")}
|
||||||
disabled={isArchiving}
|
|
||||||
>
|
>
|
||||||
{thread.archived ? (
|
<PenLine className="mr-2 h-4 w-4" />
|
||||||
|
<span>{t("rename") || "Rename"}</span>
|
||||||
|
</DropdownMenuItem>
|
||||||
|
)}
|
||||||
|
<DropdownMenuItem
|
||||||
|
onClick={() => handleToggleArchive(thread.id, thread.archived)}
|
||||||
|
disabled={isArchiving}
|
||||||
|
>
|
||||||
|
{thread.archived ? (
|
||||||
<>
|
<>
|
||||||
<RotateCcwIcon className="mr-2 h-4 w-4" />
|
<RotateCcwIcon className="mr-2 h-4 w-4" />
|
||||||
<span>{t("unarchive") || "Restore"}</span>
|
<span>{t("unarchive") || "Restore"}</span>
|
||||||
|
|
@ -412,6 +462,51 @@ export function AllSharedChatsSidebar({
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
<Dialog open={showRenameDialog} onOpenChange={setShowRenameDialog}>
|
||||||
|
<DialogContent className="sm:max-w-md">
|
||||||
|
<DialogHeader>
|
||||||
|
<DialogTitle className="flex items-center gap-2">
|
||||||
|
<span>{t("rename_chat") || "Rename Chat"}</span>
|
||||||
|
</DialogTitle>
|
||||||
|
<DialogDescription>
|
||||||
|
{t("rename_chat_description") || "Enter a new name for this conversation."}
|
||||||
|
</DialogDescription>
|
||||||
|
</DialogHeader>
|
||||||
|
<Input
|
||||||
|
value={newTitle}
|
||||||
|
onChange={(e) => setNewTitle(e.target.value)}
|
||||||
|
placeholder={t("chat_title_placeholder") || "Chat title"}
|
||||||
|
onKeyDown={(e) => {
|
||||||
|
if (e.key === "Enter" && !isRenaming && newTitle.trim()) {
|
||||||
|
handleConfirmRename();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<DialogFooter className="flex gap-2 sm:justify-end">
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
onClick={() => setShowRenameDialog(false)}
|
||||||
|
disabled={isRenaming}
|
||||||
|
>
|
||||||
|
{t("cancel")}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
onClick={handleConfirmRename}
|
||||||
|
disabled={isRenaming || !newTitle.trim()}
|
||||||
|
className="gap-2"
|
||||||
|
>
|
||||||
|
{isRenaming ? (
|
||||||
|
<>
|
||||||
|
<Spinner size="xs" />
|
||||||
|
<span>{t("renaming") || "Renaming"}</span>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<span>{t("rename") || "Rename"}</span>
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
</DialogFooter>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
</SidebarSlideOutPanel>
|
</SidebarSlideOutPanel>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ export function SidebarSlideOutPanel({
|
||||||
exit={{ x: "-100%" }}
|
exit={{ x: "-100%" }}
|
||||||
transition={{ type: "tween", duration: 0.2, ease: [0.4, 0, 0.2, 1] }}
|
transition={{ type: "tween", duration: 0.2, ease: [0.4, 0, 0.2, 1] }}
|
||||||
className={cn(
|
className={cn(
|
||||||
"h-full w-full bg-background flex flex-col pointer-events-auto",
|
"h-full w-full bg-background flex flex-col pointer-events-auto select-none",
|
||||||
"sm:border-r sm:shadow-xl"
|
"sm:border-r sm:shadow-xl"
|
||||||
)}
|
)}
|
||||||
role="dialog"
|
role="dialog"
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useAtom } from "jotai";
|
import { useAtom } from "jotai";
|
||||||
import { CheckCircle2, FileType, Info, Tag, Upload, X } from "lucide-react";
|
import { CheckCircle2, FileType, Info, Upload, X } from "lucide-react";
|
||||||
import { AnimatePresence, motion } from "motion/react";
|
import { AnimatePresence, motion } from "motion/react";
|
||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
import { useCallback, useMemo, useRef, useState } from "react";
|
import { useCallback, useMemo, useRef, useState } from "react";
|
||||||
|
|
@ -452,7 +452,6 @@ export function DocumentUploadTab({
|
||||||
<AccordionItem value="supported-file-types" className="border-0">
|
<AccordionItem value="supported-file-types" className="border-0">
|
||||||
<AccordionTrigger className="px-3 sm:px-6 py-3 sm:py-4 hover:no-underline !items-center [&>svg]:!translate-y-0">
|
<AccordionTrigger className="px-3 sm:px-6 py-3 sm:py-4 hover:no-underline !items-center [&>svg]:!translate-y-0">
|
||||||
<div className="flex items-center gap-2 flex-1">
|
<div className="flex items-center gap-2 flex-1">
|
||||||
<Tag className="h-4 w-4 sm:h-5 sm:w-5 shrink-0" />
|
|
||||||
<div className="text-left min-w-0">
|
<div className="text-left min-w-0">
|
||||||
<div className="font-semibold text-sm sm:text-base">
|
<div className="font-semibold text-sm sm:text-base">
|
||||||
{t("supported_file_types")}
|
{t("supported_file_types")}
|
||||||
|
|
|
||||||
|
|
@ -682,7 +682,7 @@
|
||||||
"rename_chat": "Rename Chat",
|
"rename_chat": "Rename Chat",
|
||||||
"rename_chat_description": "Enter a new name for this conversation.",
|
"rename_chat_description": "Enter a new name for this conversation.",
|
||||||
"chat_title_placeholder": "Chat title",
|
"chat_title_placeholder": "Chat title",
|
||||||
"renaming": "Renaming...",
|
"renaming": "Renaming",
|
||||||
"no_archived_chats": "No archived chats",
|
"no_archived_chats": "No archived chats",
|
||||||
"error_archiving_chat": "Failed to archive chat",
|
"error_archiving_chat": "Failed to archive chat",
|
||||||
"new_chat": "New chat",
|
"new_chat": "New chat",
|
||||||
|
|
@ -720,7 +720,8 @@
|
||||||
"unread": "Unread",
|
"unread": "Unread",
|
||||||
"connectors": "Connectors",
|
"connectors": "Connectors",
|
||||||
"all_connectors": "All connectors",
|
"all_connectors": "All connectors",
|
||||||
"close": "Close"
|
"close": "Close",
|
||||||
|
"cancel": "Cancel"
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"something_went_wrong": "Something went wrong",
|
"something_went_wrong": "Something went wrong",
|
||||||
|
|
|
||||||
|
|
@ -720,7 +720,8 @@
|
||||||
"unread": "No leído",
|
"unread": "No leído",
|
||||||
"connectors": "Conectores",
|
"connectors": "Conectores",
|
||||||
"all_connectors": "Todos los conectores",
|
"all_connectors": "Todos los conectores",
|
||||||
"close": "Cerrar"
|
"close": "Cerrar",
|
||||||
|
"cancel": "Cancelar"
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"something_went_wrong": "Algo salió mal",
|
"something_went_wrong": "Algo salió mal",
|
||||||
|
|
|
||||||
|
|
@ -720,7 +720,8 @@
|
||||||
"unread": "अपठित",
|
"unread": "अपठित",
|
||||||
"connectors": "कनेक्टर",
|
"connectors": "कनेक्टर",
|
||||||
"all_connectors": "सभी कनेक्टर",
|
"all_connectors": "सभी कनेक्टर",
|
||||||
"close": "बंद करें"
|
"close": "बंद करें",
|
||||||
|
"cancel": "रद्द करें"
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"something_went_wrong": "कुछ गलत हो गया",
|
"something_went_wrong": "कुछ गलत हो गया",
|
||||||
|
|
|
||||||
|
|
@ -720,7 +720,8 @@
|
||||||
"unread": "Não lido",
|
"unread": "Não lido",
|
||||||
"connectors": "Conectores",
|
"connectors": "Conectores",
|
||||||
"all_connectors": "Todos os conectores",
|
"all_connectors": "Todos os conectores",
|
||||||
"close": "Fechar"
|
"close": "Fechar",
|
||||||
|
"cancel": "Cancelar"
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"something_went_wrong": "Algo deu errado",
|
"something_went_wrong": "Algo deu errado",
|
||||||
|
|
|
||||||
|
|
@ -704,7 +704,8 @@
|
||||||
"unread": "未读",
|
"unread": "未读",
|
||||||
"connectors": "连接器",
|
"connectors": "连接器",
|
||||||
"all_connectors": "所有连接器",
|
"all_connectors": "所有连接器",
|
||||||
"close": "关闭"
|
"close": "关闭",
|
||||||
|
"cancel": "取消"
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"something_went_wrong": "出错了",
|
"something_went_wrong": "出错了",
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue