diff --git a/client/src/components/Bookmarks/BookmarkEditDialog.tsx b/client/src/components/Bookmarks/BookmarkEditDialog.tsx index b5acec6d179..a57b61088fc 100644 --- a/client/src/components/Bookmarks/BookmarkEditDialog.tsx +++ b/client/src/components/Bookmarks/BookmarkEditDialog.tsx @@ -1,8 +1,7 @@ import React, { useRef, useState } from 'react'; -import { DialogTrigger } from '@radix-ui/react-dialog'; import { TConversationTag, TConversation } from 'librechat-data-provider'; -import DialogTemplate from '~/components/ui/DialogTemplate'; -import { Dialog, DialogButton } from '~/components/ui/'; +import OGDialogTemplate from '~/components/ui/OGDialogTemplate'; +import { OGDialog, OGDialogTrigger, OGDialogClose } from '~/components/ui/'; import BookmarkForm from './BookmarkForm'; import { useLocalize } from '~/hooks'; import { Spinner } from '../svg'; @@ -33,9 +32,9 @@ const BookmarkEditDialog = ({ }; return ( - - {trigger} - + {trigger} + } buttons={ -
- +
+ + } /> -
+ ); }; diff --git a/client/src/components/Bookmarks/BookmarkForm.tsx b/client/src/components/Bookmarks/BookmarkForm.tsx index 4a6702dd689..98b84362dec 100644 --- a/client/src/components/Bookmarks/BookmarkForm.tsx +++ b/client/src/components/Bookmarks/BookmarkForm.tsx @@ -130,7 +130,7 @@ const BookmarkForm = ({ aria-invalid={!!errors.tag} className={cn( defaultTextProps, - 'flex h-10 max-h-10 w-full resize-none border-gray-100 px-3 py-2 dark:border-gray-600', + 'flex h-10 max-h-10 w-full resize-none px-3 py-2', removeFocusOutlines, )} placeholder=" " @@ -158,7 +158,7 @@ const BookmarkForm = ({ /> {conversation && ( -
+
= ({
= ({
- - - + )} + + + +
{localize('com_ui_bookmarks_new')}
+ + } + /> +
+ +
); }; export default BookmarkPanel; diff --git a/client/src/components/SidePanel/Bookmarks/BookmarkTable.tsx b/client/src/components/SidePanel/Bookmarks/BookmarkTable.tsx index 884f5dca939..3ca213a8449 100644 --- a/client/src/components/SidePanel/Bookmarks/BookmarkTable.tsx +++ b/client/src/components/SidePanel/Bookmarks/BookmarkTable.tsx @@ -1,13 +1,16 @@ import React, { useCallback, useEffect, useState } from 'react'; import type { ConversationTagsResponse, TConversationTag } from 'librechat-data-provider'; +import { Table, TableHeader, TableBody, TableRow, TableCell, Input, Button } from '~/components/ui'; import { BookmarkContext, useBookmarkContext } from '~/Providers/BookmarkContext'; import BookmarkTableRow from './BookmarkTableRow'; import { useLocalize } from '~/hooks'; -import { cn } from '~/utils'; const BookmarkTable = () => { const localize = useLocalize(); const [rows, setRows] = useState([]); + const [pageIndex, setPageIndex] = useState(0); + const [searchQuery, setSearchQuery] = useState(''); + const pageSize = 10; const { bookmarks } = useBookmarkContext(); useEffect(() => { @@ -27,30 +30,65 @@ const BookmarkTable = () => { return ; }, []); + const filteredRows = rows.filter((row) => + row.tag.toLowerCase().includes(searchQuery.toLowerCase()), + ); + + const currentRows = filteredRows.slice(pageIndex * pageSize, (pageIndex + 1) * pageSize); + return ( -
- - - -
+
+ setSearchQuery(e.target.value)} + className="w-full dark:border-gray-700" + /> +
+
+ + + +
{localize('com_ui_bookmarks_title')}
- -
- - - - - {rows.map((row, i) => renderRow(row, i))} -
+ +
{localize('com_ui_bookmarks_count')}
-
+ + + + {currentRows.map((row, i) => renderRow(row, i))} +
+
+
+
+ {localize('com_ui_showing')} {pageIndex * pageSize + 1} -{' '} + {Math.min((pageIndex + 1) * pageSize, filteredRows.length)} {localize('com_ui_of')}{' '} + {filteredRows.length} +
+
+ + +
); diff --git a/client/src/components/SidePanel/Bookmarks/BookmarkTableRow.tsx b/client/src/components/SidePanel/Bookmarks/BookmarkTableRow.tsx index 916a1830436..9923fe73982 100644 --- a/client/src/components/SidePanel/Bookmarks/BookmarkTableRow.tsx +++ b/client/src/components/SidePanel/Bookmarks/BookmarkTableRow.tsx @@ -1,64 +1,22 @@ -import { useRef } from 'react'; +import React, { useState } from 'react'; import { useDrag, useDrop } from 'react-dnd'; -import type { FC } from 'react'; -import type { Identifier, XYCoord } from 'dnd-core'; import type { TConversationTag } from 'librechat-data-provider'; import { DeleteBookmarkButton, EditBookmarkButton } from '~/components/Bookmarks'; -import { useConversationTagMutation } from '~/data-provider'; -import { NotificationSeverity } from '~/common'; -import { useToastContext } from '~/Providers'; -import { useLocalize } from '~/hooks'; -import { cn } from '~/utils'; +import { TableRow, TableCell } from '~/components/ui'; -export const ItemTypes = { - CARD: 'card', -}; - -export interface BookmarkItemProps { - position: number; - moveRow: (dragIndex: number, hoverIndex: number) => void; +interface BookmarkTableRowProps { row: TConversationTag; + moveRow: (dragIndex: number, hoverIndex: number) => void; + position: number; } -interface DragItem { - index: number; - id: string; - type: string; -} - -const BookmarkTableRow: FC = ({ position, moveRow, row, ...rest }) => { - const ref = useRef(null); - - const mutation = useConversationTagMutation(row.tag); - const localize = useLocalize(); - const { showToast } = useToastContext(); +const BookmarkTableRow: React.FC = ({ row, moveRow, position }) => { + const [isHovered, setIsHovered] = useState(false); + const ref = React.useRef(null); - const handleDrop = (item: DragItem) => { - const data = { - ...row, - position: item.index, - }; - mutation.mutate(data, { - onError: () => { - showToast({ - message: localize('com_endpoint_preset_save_error'), - severity: NotificationSeverity.ERROR, - }); - }, - }); - }; - - const [{ handlerId }, drop] = useDrop({ - accept: ItemTypes.CARD, - collect(monitor) { - return { - handlerId: monitor.getHandlerId(), - }; - }, - drop(item: DragItem, monitor) { - handleDrop(item); - }, - hover(item: DragItem, monitor) { + const [, drop] = useDrop({ + accept: 'bookmark', + hover(item: { index: number }) { if (!ref.current) { return; } @@ -67,68 +25,60 @@ const BookmarkTableRow: FC = ({ position, moveRow, row, ...re if (dragIndex === hoverIndex) { return; } - - const hoverBoundingRect = ref.current?.getBoundingClientRect(); - - const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2; - - const clientOffset = monitor.getClientOffset(); - - const hoverClientY = (clientOffset as XYCoord).y - hoverBoundingRect.top; - - if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) { - return; - } - if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) { - return; - } - moveRow(dragIndex, hoverIndex); - item.index = hoverIndex; }, }); const [{ isDragging }, drag] = useDrag({ - type: ItemTypes.CARD, - item: () => { - return { id: row.tag, index: position }; - }, + type: 'bookmark', + item: { index: position }, collect: (monitor) => ({ isDragging: monitor.isDragging(), }), }); - if (position > 0) { - drag(drop(ref)); - } + drag(drop(ref)); return ( - setIsHovered(true)} + onMouseLeave={() => setIsHovered(false)} > - {row.tag} - - {row.count} - - - {position > 0 && ( -
- - + +
{row.tag}
+
+ +
+
{row.count}
+
setIsHovered(true)} + onBlur={() => setIsHovered(false)} + > + setIsHovered(true)} + onBlur={() => setIsHovered(false)} + /> + setIsHovered(true)} + onBlur={() => setIsHovered(false)} + />
- )} - - +
+
+ ); }; diff --git a/client/src/components/SidePanel/Builder/AssistantTool.tsx b/client/src/components/SidePanel/Builder/AssistantTool.tsx index ff1d004ee01..7ebde003c5d 100644 --- a/client/src/components/SidePanel/Builder/AssistantTool.tsx +++ b/client/src/components/SidePanel/Builder/AssistantTool.tsx @@ -88,7 +88,6 @@ export default function AssistantTool({ diff --git a/client/src/components/SidePanel/Files/PanelTable.tsx b/client/src/components/SidePanel/Files/PanelTable.tsx index c75bf0774b5..69f025a74da 100644 --- a/client/src/components/SidePanel/Files/PanelTable.tsx +++ b/client/src/components/SidePanel/Files/PanelTable.tsx @@ -72,12 +72,12 @@ export default function DataTable({ columns, data }: DataTablePro return ( <> -
+
table.getColumn('filename')?.setFilterValue(event.target.value)} - className="max-w-xs dark:border-gray-700" + className="w-full dark:border-gray-700" />
@@ -90,7 +90,7 @@ export default function DataTable({ columns, data }: DataTablePro {header.isPlaceholder ? null @@ -133,17 +133,19 @@ export default function DataTable({ columns, data }: DataTablePro
-
- -
+
+
+ +
+
); } return ( - - - - - + + + + -
-
{confirmMessage}
-
- - } + main={} selection={{ selectHandler: confirm, selectClasses: @@ -83,6 +91,6 @@ export default function TooltipIcon({ selectText: localize('com_ui_delete'), }} /> -
+ ); } diff --git a/client/src/hooks/Nav/useSideNavLinks.ts b/client/src/hooks/Nav/useSideNavLinks.ts index 46dbd8b40eb..6b90a98ea08 100644 --- a/client/src/hooks/Nav/useSideNavLinks.ts +++ b/client/src/hooks/Nav/useSideNavLinks.ts @@ -13,6 +13,7 @@ import { } from 'librechat-data-provider'; import type { TConfig, TInterfaceConfig } from 'librechat-data-provider'; import type { NavLink } from '~/common'; +import BookmarkPanel from '~/components/SidePanel/Bookmarks/BookmarkPanel'; import PanelSwitch from '~/components/SidePanel/Builder/PanelSwitch'; import PromptsAccordion from '~/components/Prompts/PromptsAccordion'; // import Parameters from '~/components/SidePanel/Parameters/Panel'; @@ -26,14 +27,12 @@ export default function useSideNavLinks({ keyProvided, endpoint, interfaceConfig, - manageBookmarks, }: { hidePanel: () => void; assistants?: TConfig | null; keyProvided: boolean; endpoint?: EModelEndpoint | null; interfaceConfig: Partial; - manageBookmarks: (e?: React.MouseEvent) => void; }) { const hasAccessToPrompts = useHasAccess({ permissionType: PermissionTypes.PROMPTS, @@ -80,8 +79,8 @@ export default function useSideNavLinks({ title: 'com_sidepanel_conversation_tags', label: '', icon: Bookmark, - onClick: manageBookmarks, id: 'bookmarks', + Component: BookmarkPanel, }); links.push({ @@ -100,7 +99,6 @@ export default function useSideNavLinks({ endpoint, interfaceConfig.parameters, hasAccessToPrompts, - manageBookmarks, ]); return Links; diff --git a/client/src/localization/languages/Eng.ts b/client/src/localization/languages/Eng.ts index bc8bde3dc78..a521360d94d 100644 --- a/client/src/localization/languages/Eng.ts +++ b/client/src/localization/languages/Eng.ts @@ -307,6 +307,7 @@ export default { com_ui_bookmarks_update_error: 'There was an error updating the bookmark', com_ui_bookmarks_delete_error: 'There was an error deleting the bookmark', com_ui_bookmarks_add_to_conversation: 'Add to current conversation', + com_ui_bookmarks_filter: 'Filter bookmarks...', com_auth_error_login: 'Unable to login with the information provided. Please check your credentials and try again.', com_auth_error_login_rl: