LibreChat/client/src/components/SidePanel/Memories/MemoryPanel.tsx

230 lines
7.6 KiB
TypeScript
Raw Normal View History

🪄 refactor: UI Polish and Admin Dialog Unification (#11108) * refactor(OpenSidebar): removed useless classNames * style(Header): update hover styles across various components for improved UI consistency * style(Nav): update hover styles in AccountSettings and SearchBar for improved UI consistency * style: update button classes for consistent hover effects and improved UI responsiveness * style(Nav, OpenSidebar, Header, Convo): improve UI responsiveness and animation transitions * style(PresetsMenu, NewChat): update icon sizes and improve component styling for better UI consistency * style(Nav, Root): enhance sidebar mobile animations and responsiveness for better UI experience * style(ExportAndShareMenu, BookmarkMenu): update icon sizes for improved UI consistency * style: remove transition duration from button classes for improved UI responsiveness * style(CustomMenu, ModelSelector): update background colors for improved UI consistency and responsiveness * style(ExportAndShareMenu): update icon color for improved UI consistency * style(TemporaryChat): refine button styles for improved UI consistency and responsiveness * style(BookmarkNav): refactor to use DropdownPopup and remove BookmarkNavItems for improved UI consistency and functionality * style(CustomMenu, EndpointItem): enhance UI elements for improved consistency and accessibility * style(EndpointItem): adjust gap in icon container for improved layout consistency * style(CustomMenu, EndpointItem): update focus ring color for improved UI consistency * style(EndpointItem): update icon color for improved UI consistency in dark theme * style: update focus styles for improved accessibility and consistency across components * refactor(Nav): extract sidebar width to NAV_WIDTH constant Centralize mobile (320px) and desktop (260px) sidebar widths in a single exported constant to avoid magic numbers and ensure consistency. * fix(BookmarkNav): memoize handlers used in useMemo Wrap handleTagClick and handleClear in useCallback and add them to the dropdownItems useMemo dependency array to prevent stale closures. * feat: introduce FilterInput component and replace existing inputs with it across multiple components * feat(DataTable): replace custom input with FilterInput component for improved filtering * fix: Nested dialog overlay stacking issue Fixes overlay appearing behind content when opening nested dialogs. Introduced dynamic z-index calculation based on dialog depth using React context. - First dialog: overlay z-50, content z-100 - Nested dialogs increment by 60: overlay z-110/content z-160, etc. Preserves a11y escape key handling from #10975 and #10851. Regression from #11008 (afb67fcf1) which increased content z-index without adjusting overlay z-index for nested dialog scenarios. * Refactor admin settings components to use a unified AdminSettingsDialog - Removed redundant code from AdminSettings, MCPAdminSettings, and Memories AdminSettings components. - Introduced AdminSettingsDialog component to handle permission management for different sections. - Updated permission handling logic to use a consistent structure across components. - Enhanced role selection and permission confirmation features in the new dialog. - Improved UI consistency and maintainability by centralizing dialog functionality. * refactor(Memory): memory management UI components and replace MemoryViewer with MemoryPanel * refactor(Memory): enhance UI components for Memory dialogs and improve input styling * refactor(Bookmarks): improve bookmark management UI with enhanced styling * refactor(translations): remove redundant filter input and bookmark count entries * refactor(Convo): integrate useShiftKey hook for enhanced keyboard interaction and improve UI responsiveness
2025-12-28 17:01:25 +01:00
import { useMemo, useState, useEffect } from 'react';
import { Plus } from 'lucide-react';
import { matchSorter } from 'match-sorter';
import { SystemRoles, PermissionTypes, Permissions } from 'librechat-data-provider';
import {
Button,
Switch,
Spinner,
FilterInput,
TooltipAnchor,
OGDialogTrigger,
useToastContext,
} from '@librechat/client';
import type { TUserMemory } from 'librechat-data-provider';
import {
useUpdateMemoryPreferencesMutation,
useMemoriesQuery,
useGetUserQuery,
} from '~/data-provider';
import { useLocalize, useAuthContext, useHasAccess } from '~/hooks';
import MemoryCreateDialog from './MemoryCreateDialog';
import MemoryUsageBadge from './MemoryUsageBadge';
import AdminSettings from './AdminSettings';
import MemoryList from './MemoryList';
const pageSize = 10;
export default function MemoryPanel() {
const localize = useLocalize();
const { user } = useAuthContext();
const { data: userData } = useGetUserQuery();
const { data: memData, isLoading } = useMemoriesQuery();
const { showToast } = useToastContext();
const [pageIndex, setPageIndex] = useState(0);
const [searchQuery, setSearchQuery] = useState('');
const [createDialogOpen, setCreateDialogOpen] = useState(false);
const [referenceSavedMemories, setReferenceSavedMemories] = useState(true);
const updateMemoryPreferencesMutation = useUpdateMemoryPreferencesMutation({
onSuccess: () => {
showToast({
message: localize('com_ui_preferences_updated'),
status: 'success',
});
},
onError: () => {
showToast({
message: localize('com_ui_error_updating_preferences'),
status: 'error',
});
setReferenceSavedMemories((prev) => !prev);
},
});
useEffect(() => {
if (userData?.personalization?.memories !== undefined) {
setReferenceSavedMemories(userData.personalization.memories);
}
}, [userData?.personalization?.memories]);
const handleMemoryToggle = (checked: boolean) => {
setReferenceSavedMemories(checked);
updateMemoryPreferencesMutation.mutate({ memories: checked });
};
const hasReadAccess = useHasAccess({
permissionType: PermissionTypes.MEMORIES,
permission: Permissions.READ,
});
const hasUpdateAccess = useHasAccess({
permissionType: PermissionTypes.MEMORIES,
permission: Permissions.UPDATE,
});
const hasCreateAccess = useHasAccess({
permissionType: PermissionTypes.MEMORIES,
permission: Permissions.CREATE,
});
const hasOptOutAccess = useHasAccess({
permissionType: PermissionTypes.MEMORIES,
permission: Permissions.OPT_OUT,
});
const memories: TUserMemory[] = useMemo(() => memData?.memories ?? [], [memData]);
const filteredMemories = useMemo(() => {
return matchSorter(memories, searchQuery, {
keys: ['key', 'value'],
});
}, [memories, searchQuery]);
const currentRows = useMemo(() => {
return filteredMemories.slice(pageIndex * pageSize, (pageIndex + 1) * pageSize);
}, [filteredMemories, pageIndex]);
// Reset page when search changes
useEffect(() => {
setPageIndex(0);
}, [searchQuery]);
if (isLoading) {
return (
<div className="flex h-full w-full items-center justify-center p-4">
<Spinner />
</div>
);
}
if (!hasReadAccess) {
return (
<div className="flex h-full w-full items-center justify-center p-4">
<div className="text-center">
<p className="text-sm text-text-secondary">{localize('com_ui_no_read_access')}</p>
</div>
</div>
);
}
const totalPages = Math.ceil(filteredMemories.length / pageSize);
return (
🎨 refactor: Redesign Sidebar with Unified Icon Strip Layout (#12013) * fix: Graceful SidePanelContext handling when ChatContext unavailable The UnifiedSidebar component is rendered at the Root level before ChatContext is provided (which happens only in ChatRoute). This caused an error when useSidePanelContext tried to call useChatContext before it was available. Changes: - Made SidePanelProvider gracefully handle missing ChatContext with try/catch - Changed useSidePanelContext to return a safe default instead of throwing - Prevents render error on application load and improves robustness * fix: Provide default context value for ChatContext to prevent setFilesLoading errors The ChatContext was initialized with an empty object as default, causing 'setFilesLoading is not a function' errors when components tried to call functions from the context. This fix provides a proper default context with no-op functions for all expected properties. Fixes FileRow component errors that occurred when navigating to sections with file upload functionality (Agent Builder, Attach Files, etc.). * fix: Move ChatFormProvider to Root to fix Prompts sidebar rendering The ChatFormProvider was only wrapping ChatView, but the sidebar (including Prompts) renders separately and needs access to the ChatFormContext. ChatGroupItem uses useSubmitMessage which calls useChatFormContext, causing a React error when Prompts were accessed. This fix moves the ChatFormProvider to the Root component to wrap both the sidebar and the main chat view, ensuring the form context is available throughout the entire application. * fix: Active section switching and dead code cleanup Sync ActivePanelProvider state when defaultActive prop changes so clicking a collapsed-bar icon actually switches the expanded section. Remove the now-unused hideSidePanel atom and its Settings toggle. * style: Redesign sidebar layout with optimized spacing and positioning - Remove duplicate new chat button from sidebar, keep it in main header - Reposition account settings to bottom of expanded sidebar - Simplify collapsed bar padding and alignment - Clean up unused framer-motion imports from Header - Optimize vertical space usage in expanded panel - Align search bar icon color with sidebar theme * fix: Chat history not showing in sidebar Add h-full to ConversationsSection outer div so it fills the Nav content panel, giving react-virtualized's AutoSizer a measurable height. Change Nav content panel from overflow-y-auto to overflow-hidden since the virtualized list handles its own scrolling. * refactor: Move nav icons to fixed icon strip alongside sidebar toggle Extract section icons from the Nav content panel into the ExpandedPanel icon strip, matching the CollapsedBar layout. Both states now share identical button styling and 50px width, eliminating layout shift on toggle. Nav.tsx simplified to content-only rendering. Set text-text-primary on Nav content for consistent child text color. * refactor: sidebar components and remove unused NewChat component * refactor: streamline sidebar components and introduce NewChat button * refactor: enhance sidebar functionality with expanded state management and improved layout * fix: re-implement sidebar resizing functionality with mouse events * feat: enhance sidebar layout responsiveness on mobile * refactor: remove unused components and streamline sidebar functionality * feat: enhance sidebar behavior with responsive transformations for small screens * feat: add new chat button for small screens with message cache clearing * feat: improve state management in sidebar and marketplace components * feat: enhance scrolling behavior in AgentPanel and Nav components * fix: normalize sidebar panel font sizes and default panel selection Set text-sm as base font size on the shared Nav container so all panels render consistently. Guard against empty localStorage value when restoring the active sidebar panel. * fix: adjust avatar size and class for collapsed state in AccountSettings component * style: adjust padding and class names in Nav, Parameters, and ConversationsSection components * fix: close mobile sidebar on pinned favorite selection * refactor: remove unused key in translation file * fix: Address review findings for unified sidebar - Restore ChatFormProvider per-ChatView to fix multi-conversation input isolation; add separate ChatFormProvider in UnifiedSidebar for Prompts panel access - Add inert attribute on mobile sidebar (when collapsed) and main content (when sidebar overlay is open) to prevent keyboard focus leaking - Replace unsafe `as unknown as TChatContext` cast with null-based context that throws descriptively when used outside a provider - Throttle mousemove resize handler with requestAnimationFrame to prevent React state updates at 120Hz during sidebar drag - Unify active panel state: remove split between activeSection in UnifiedSidebar and internal state in ActivePanelContext; single source of truth with localStorage sync on every write - Delete orphaned SidePanelProvider/useSidePanelContext (no consumers after SidePanel.tsx removal) - Add data-testid="new-chat-button" to NewChat component - Add includeHidePanel option to useSideNavLinks; remove no-op hidePanel callback and post-hoc filter in useUnifiedSidebarLinks - Close sidebar on first mobile visit when localStorage has no prior state - Remove unnecessary min-width/max-width CSS transitions (only width needed) - Remove dead SideNav re-export from SidePanel/index.ts - Remove duplicate aria-label from Sidebar nav element - Fix trailing blank line in mobile.css * style: fix prettier formatting in Root.tsx * fix: Address remaining review findings and re-render isolation - Extract useChatHelpers(0) into SidebarChatProvider child component so Recoil atom subscriptions (streaming tokens, latestMessage, etc.) only re-render the active panel — not the sidebar shell, resize logic, or icon strip (Finding 4) - Fix prompt pre-fill when sidebar form context differs from chat form: useSubmitMessage now reads the actual textarea DOM value via mainTextareaId as fallback for the currentText newline check (Finding 1) - Add id="close-sidebar-button" and data-testid to ExpandedPanel toggle so OpenSidebar focus management works after expand (Finding 10/N3) - Replace Dispatch<SetStateAction<number>> prop with onResizeKeyboard(direction) callback on Sidebar (Finding 13) - Fix first-mobile-visit sidebar flash: atom default now checks window.matchMedia at init time instead of defaulting to true then correcting in a useEffect; removes eslint-disable suppression (N1/N2) - Add tests for ActivePanelContext and ChatContext (Finding 8) * refactor: remove no-op memo from SidebarChatProvider memo(SidebarChatProvider) provided no memoization because its only prop (children) is inline JSX — a new reference on every parent render. The streaming isolation works through Recoil subscription scoping, not memo. Clarified in the JSDoc comment. * fix: add shebang to pre-commit hook for Windows compatibility Git on Windows cannot spawn hook scripts without a shebang line, causing 'cannot spawn .husky/pre-commit: No such file or directory'. * style: fix sidebar panel styling inconsistencies - Remove inner overflow-y-auto from AgentPanel form to eliminate double scrollbars when nested inside Nav.tsx's scroll container - Add consistent padding (px-3 py-2) to Nav.tsx panel container - Remove hardcoded 150px cell widths from Files PanelTable; widen date column from 25% to 35% so dates are no longer cut off - Compact pagination row with flex-wrap and smaller text - Add px-1 padding to Parameters panel for consistency - Change overflow-x-visible to overflow-x-hidden on Files and Bookmarks panels to prevent horizontal overflow * fix: Restore panel styling regressions in unified sidebar - Nav.tsx wrapper: remove extra px-3 padding, add hide-scrollbar class, restore py-1 to match old ResizablePanel wrapper - AgentPanel: restore scrollbar-gutter-stable and mx-1 margin (was px-1) - Parameters/Panel: restore p-3 padding (was px-1 pt-1) - Files/Panel: restore overflow-x-visible (was hidden, clipping content) - Files/PanelTable: restore 75/25 column widths, restore 150px cell width constraints, restore pagination text-sm and gap-2 - Bookmarks/Panel: restore overflow-x-visible * style: initial improvements post-sidenav change * style: update text size in DynamicTextarea for improved readability * style: update FilterPrompts alignment in PromptsAccordion for better layout consistency * style: adjust component heights and padding for consistency across SidePanel elements - Updated height from 40px to 36px in AgentSelect for uniformity - Changed button size class from "bg-transparent" to "size-9" in BookmarkTable, MCPBuilderPanel, and MemoryPanel - Added padding class "py-1.5" in DynamicDropdown for improved spacing - Reduced height from 10 to 9 in DynamicInput and DynamicTags for a cohesive look - Adjusted padding in Parameters/Panel for better layout * style: standardize button sizes and icon dimensions across chat components - Updated button size class from 'size-10' to 'size-9' in multiple components for consistency. - Adjusted icon sizes from 'icon-lg' to 'icon-md' in various locations to maintain uniformity. - Modified header height for better alignment with design specifications. * style: enhance layout consistency and component structure across various panels - Updated ActivePanelContext to utilize useCallback and useMemo for improved performance. - Adjusted padding and layout in multiple SidePanel components for better visual alignment. - Standardized icon sizes and button dimensions in AddMultiConvo and other components. - Improved overall spacing and structure in PromptsAccordion, MemoryPanel, and FilesPanel for a cohesive design. * style: standardize component heights and text sizes across various panels - Adjusted button heights from 10px to 9px in multiple components for consistency. - Updated text sizes from 'text-sm' to 'text-xs' in DynamicCheckbox, DynamicCombobox, DynamicDropdown, DynamicInput, DynamicSlider, DynamicSwitch, DynamicTags, and DynamicTextarea for improved readability. - Added portal prop to account settings menu for better rendering behavior. * refactor: optimize Tooltip component structure for performance - Introduced a new memoized TooltipPopup component to prevent unnecessary re-renders of the TooltipAnchor when the tooltip mounts/unmounts. - Updated TooltipAnchor to utilize the new TooltipPopup, improving separation of concerns and enhancing performance. - Maintained existing functionality while improving code clarity and maintainability. * refactor: improve sidebar transition handling for better responsiveness - Enhanced the transition properties in the UnifiedSidebar component to include min-width and max-width adjustments, ensuring smoother resizing behavior. - Cleaned up import statements by removing unnecessary lines for better code clarity. * fix: prevent text selection during sidebar resizing - Added functionality to disable text selection on the body while the sidebar is being resized, enhancing user experience during interactions. - Restored text selection capability once resizing is complete, ensuring normal behavior resumes. * fix: ensure Header component is always rendered in ChatView - Removed conditional rendering of the Header component to ensure it is always displayed, improving the consistency of the chat interface. * refactor: add NewChatButton to ExpandedPanel for improved user interaction - Introduced a NewChatButton component in the ExpandedPanel, allowing users to initiate new conversations easily. - Implemented functionality to clear message cache and invalidate queries upon button click, enhancing performance and user experience. - Restored import statements for OpenSidebar and PresetsMenu in Header component for better organization. --------- Co-authored-by: Danny Avila <danny@librechat.ai>
2026-03-22 06:15:20 +01:00
<div className="flex h-auto w-full flex-col px-3 pb-3">
<div role="region" aria-label={localize('com_ui_memories')} className="space-y-2">
🪄 refactor: UI Polish and Admin Dialog Unification (#11108) * refactor(OpenSidebar): removed useless classNames * style(Header): update hover styles across various components for improved UI consistency * style(Nav): update hover styles in AccountSettings and SearchBar for improved UI consistency * style: update button classes for consistent hover effects and improved UI responsiveness * style(Nav, OpenSidebar, Header, Convo): improve UI responsiveness and animation transitions * style(PresetsMenu, NewChat): update icon sizes and improve component styling for better UI consistency * style(Nav, Root): enhance sidebar mobile animations and responsiveness for better UI experience * style(ExportAndShareMenu, BookmarkMenu): update icon sizes for improved UI consistency * style: remove transition duration from button classes for improved UI responsiveness * style(CustomMenu, ModelSelector): update background colors for improved UI consistency and responsiveness * style(ExportAndShareMenu): update icon color for improved UI consistency * style(TemporaryChat): refine button styles for improved UI consistency and responsiveness * style(BookmarkNav): refactor to use DropdownPopup and remove BookmarkNavItems for improved UI consistency and functionality * style(CustomMenu, EndpointItem): enhance UI elements for improved consistency and accessibility * style(EndpointItem): adjust gap in icon container for improved layout consistency * style(CustomMenu, EndpointItem): update focus ring color for improved UI consistency * style(EndpointItem): update icon color for improved UI consistency in dark theme * style: update focus styles for improved accessibility and consistency across components * refactor(Nav): extract sidebar width to NAV_WIDTH constant Centralize mobile (320px) and desktop (260px) sidebar widths in a single exported constant to avoid magic numbers and ensure consistency. * fix(BookmarkNav): memoize handlers used in useMemo Wrap handleTagClick and handleClear in useCallback and add them to the dropdownItems useMemo dependency array to prevent stale closures. * feat: introduce FilterInput component and replace existing inputs with it across multiple components * feat(DataTable): replace custom input with FilterInput component for improved filtering * fix: Nested dialog overlay stacking issue Fixes overlay appearing behind content when opening nested dialogs. Introduced dynamic z-index calculation based on dialog depth using React context. - First dialog: overlay z-50, content z-100 - Nested dialogs increment by 60: overlay z-110/content z-160, etc. Preserves a11y escape key handling from #10975 and #10851. Regression from #11008 (afb67fcf1) which increased content z-index without adjusting overlay z-index for nested dialog scenarios. * Refactor admin settings components to use a unified AdminSettingsDialog - Removed redundant code from AdminSettings, MCPAdminSettings, and Memories AdminSettings components. - Introduced AdminSettingsDialog component to handle permission management for different sections. - Updated permission handling logic to use a consistent structure across components. - Enhanced role selection and permission confirmation features in the new dialog. - Improved UI consistency and maintainability by centralizing dialog functionality. * refactor(Memory): memory management UI components and replace MemoryViewer with MemoryPanel * refactor(Memory): enhance UI components for Memory dialogs and improve input styling * refactor(Bookmarks): improve bookmark management UI with enhanced styling * refactor(translations): remove redundant filter input and bookmark count entries * refactor(Convo): integrate useShiftKey hook for enhanced keyboard interaction and improve UI responsiveness
2025-12-28 17:01:25 +01:00
{/* Header: Filter + Create Button */}
<div className="flex items-center gap-2">
<FilterInput
inputId="memory-search"
label={localize('com_ui_memories_filter')}
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
containerClassName="flex-1"
/>
{hasCreateAccess && (
<MemoryCreateDialog open={createDialogOpen} onOpenChange={setCreateDialogOpen}>
<OGDialogTrigger asChild>
<TooltipAnchor
description={localize('com_ui_create_memory')}
side="bottom"
render={
<Button
variant="outline"
size="icon"
🎨 refactor: Redesign Sidebar with Unified Icon Strip Layout (#12013) * fix: Graceful SidePanelContext handling when ChatContext unavailable The UnifiedSidebar component is rendered at the Root level before ChatContext is provided (which happens only in ChatRoute). This caused an error when useSidePanelContext tried to call useChatContext before it was available. Changes: - Made SidePanelProvider gracefully handle missing ChatContext with try/catch - Changed useSidePanelContext to return a safe default instead of throwing - Prevents render error on application load and improves robustness * fix: Provide default context value for ChatContext to prevent setFilesLoading errors The ChatContext was initialized with an empty object as default, causing 'setFilesLoading is not a function' errors when components tried to call functions from the context. This fix provides a proper default context with no-op functions for all expected properties. Fixes FileRow component errors that occurred when navigating to sections with file upload functionality (Agent Builder, Attach Files, etc.). * fix: Move ChatFormProvider to Root to fix Prompts sidebar rendering The ChatFormProvider was only wrapping ChatView, but the sidebar (including Prompts) renders separately and needs access to the ChatFormContext. ChatGroupItem uses useSubmitMessage which calls useChatFormContext, causing a React error when Prompts were accessed. This fix moves the ChatFormProvider to the Root component to wrap both the sidebar and the main chat view, ensuring the form context is available throughout the entire application. * fix: Active section switching and dead code cleanup Sync ActivePanelProvider state when defaultActive prop changes so clicking a collapsed-bar icon actually switches the expanded section. Remove the now-unused hideSidePanel atom and its Settings toggle. * style: Redesign sidebar layout with optimized spacing and positioning - Remove duplicate new chat button from sidebar, keep it in main header - Reposition account settings to bottom of expanded sidebar - Simplify collapsed bar padding and alignment - Clean up unused framer-motion imports from Header - Optimize vertical space usage in expanded panel - Align search bar icon color with sidebar theme * fix: Chat history not showing in sidebar Add h-full to ConversationsSection outer div so it fills the Nav content panel, giving react-virtualized's AutoSizer a measurable height. Change Nav content panel from overflow-y-auto to overflow-hidden since the virtualized list handles its own scrolling. * refactor: Move nav icons to fixed icon strip alongside sidebar toggle Extract section icons from the Nav content panel into the ExpandedPanel icon strip, matching the CollapsedBar layout. Both states now share identical button styling and 50px width, eliminating layout shift on toggle. Nav.tsx simplified to content-only rendering. Set text-text-primary on Nav content for consistent child text color. * refactor: sidebar components and remove unused NewChat component * refactor: streamline sidebar components and introduce NewChat button * refactor: enhance sidebar functionality with expanded state management and improved layout * fix: re-implement sidebar resizing functionality with mouse events * feat: enhance sidebar layout responsiveness on mobile * refactor: remove unused components and streamline sidebar functionality * feat: enhance sidebar behavior with responsive transformations for small screens * feat: add new chat button for small screens with message cache clearing * feat: improve state management in sidebar and marketplace components * feat: enhance scrolling behavior in AgentPanel and Nav components * fix: normalize sidebar panel font sizes and default panel selection Set text-sm as base font size on the shared Nav container so all panels render consistently. Guard against empty localStorage value when restoring the active sidebar panel. * fix: adjust avatar size and class for collapsed state in AccountSettings component * style: adjust padding and class names in Nav, Parameters, and ConversationsSection components * fix: close mobile sidebar on pinned favorite selection * refactor: remove unused key in translation file * fix: Address review findings for unified sidebar - Restore ChatFormProvider per-ChatView to fix multi-conversation input isolation; add separate ChatFormProvider in UnifiedSidebar for Prompts panel access - Add inert attribute on mobile sidebar (when collapsed) and main content (when sidebar overlay is open) to prevent keyboard focus leaking - Replace unsafe `as unknown as TChatContext` cast with null-based context that throws descriptively when used outside a provider - Throttle mousemove resize handler with requestAnimationFrame to prevent React state updates at 120Hz during sidebar drag - Unify active panel state: remove split between activeSection in UnifiedSidebar and internal state in ActivePanelContext; single source of truth with localStorage sync on every write - Delete orphaned SidePanelProvider/useSidePanelContext (no consumers after SidePanel.tsx removal) - Add data-testid="new-chat-button" to NewChat component - Add includeHidePanel option to useSideNavLinks; remove no-op hidePanel callback and post-hoc filter in useUnifiedSidebarLinks - Close sidebar on first mobile visit when localStorage has no prior state - Remove unnecessary min-width/max-width CSS transitions (only width needed) - Remove dead SideNav re-export from SidePanel/index.ts - Remove duplicate aria-label from Sidebar nav element - Fix trailing blank line in mobile.css * style: fix prettier formatting in Root.tsx * fix: Address remaining review findings and re-render isolation - Extract useChatHelpers(0) into SidebarChatProvider child component so Recoil atom subscriptions (streaming tokens, latestMessage, etc.) only re-render the active panel — not the sidebar shell, resize logic, or icon strip (Finding 4) - Fix prompt pre-fill when sidebar form context differs from chat form: useSubmitMessage now reads the actual textarea DOM value via mainTextareaId as fallback for the currentText newline check (Finding 1) - Add id="close-sidebar-button" and data-testid to ExpandedPanel toggle so OpenSidebar focus management works after expand (Finding 10/N3) - Replace Dispatch<SetStateAction<number>> prop with onResizeKeyboard(direction) callback on Sidebar (Finding 13) - Fix first-mobile-visit sidebar flash: atom default now checks window.matchMedia at init time instead of defaulting to true then correcting in a useEffect; removes eslint-disable suppression (N1/N2) - Add tests for ActivePanelContext and ChatContext (Finding 8) * refactor: remove no-op memo from SidebarChatProvider memo(SidebarChatProvider) provided no memoization because its only prop (children) is inline JSX — a new reference on every parent render. The streaming isolation works through Recoil subscription scoping, not memo. Clarified in the JSDoc comment. * fix: add shebang to pre-commit hook for Windows compatibility Git on Windows cannot spawn hook scripts without a shebang line, causing 'cannot spawn .husky/pre-commit: No such file or directory'. * style: fix sidebar panel styling inconsistencies - Remove inner overflow-y-auto from AgentPanel form to eliminate double scrollbars when nested inside Nav.tsx's scroll container - Add consistent padding (px-3 py-2) to Nav.tsx panel container - Remove hardcoded 150px cell widths from Files PanelTable; widen date column from 25% to 35% so dates are no longer cut off - Compact pagination row with flex-wrap and smaller text - Add px-1 padding to Parameters panel for consistency - Change overflow-x-visible to overflow-x-hidden on Files and Bookmarks panels to prevent horizontal overflow * fix: Restore panel styling regressions in unified sidebar - Nav.tsx wrapper: remove extra px-3 padding, add hide-scrollbar class, restore py-1 to match old ResizablePanel wrapper - AgentPanel: restore scrollbar-gutter-stable and mx-1 margin (was px-1) - Parameters/Panel: restore p-3 padding (was px-1 pt-1) - Files/Panel: restore overflow-x-visible (was hidden, clipping content) - Files/PanelTable: restore 75/25 column widths, restore 150px cell width constraints, restore pagination text-sm and gap-2 - Bookmarks/Panel: restore overflow-x-visible * style: initial improvements post-sidenav change * style: update text size in DynamicTextarea for improved readability * style: update FilterPrompts alignment in PromptsAccordion for better layout consistency * style: adjust component heights and padding for consistency across SidePanel elements - Updated height from 40px to 36px in AgentSelect for uniformity - Changed button size class from "bg-transparent" to "size-9" in BookmarkTable, MCPBuilderPanel, and MemoryPanel - Added padding class "py-1.5" in DynamicDropdown for improved spacing - Reduced height from 10 to 9 in DynamicInput and DynamicTags for a cohesive look - Adjusted padding in Parameters/Panel for better layout * style: standardize button sizes and icon dimensions across chat components - Updated button size class from 'size-10' to 'size-9' in multiple components for consistency. - Adjusted icon sizes from 'icon-lg' to 'icon-md' in various locations to maintain uniformity. - Modified header height for better alignment with design specifications. * style: enhance layout consistency and component structure across various panels - Updated ActivePanelContext to utilize useCallback and useMemo for improved performance. - Adjusted padding and layout in multiple SidePanel components for better visual alignment. - Standardized icon sizes and button dimensions in AddMultiConvo and other components. - Improved overall spacing and structure in PromptsAccordion, MemoryPanel, and FilesPanel for a cohesive design. * style: standardize component heights and text sizes across various panels - Adjusted button heights from 10px to 9px in multiple components for consistency. - Updated text sizes from 'text-sm' to 'text-xs' in DynamicCheckbox, DynamicCombobox, DynamicDropdown, DynamicInput, DynamicSlider, DynamicSwitch, DynamicTags, and DynamicTextarea for improved readability. - Added portal prop to account settings menu for better rendering behavior. * refactor: optimize Tooltip component structure for performance - Introduced a new memoized TooltipPopup component to prevent unnecessary re-renders of the TooltipAnchor when the tooltip mounts/unmounts. - Updated TooltipAnchor to utilize the new TooltipPopup, improving separation of concerns and enhancing performance. - Maintained existing functionality while improving code clarity and maintainability. * refactor: improve sidebar transition handling for better responsiveness - Enhanced the transition properties in the UnifiedSidebar component to include min-width and max-width adjustments, ensuring smoother resizing behavior. - Cleaned up import statements by removing unnecessary lines for better code clarity. * fix: prevent text selection during sidebar resizing - Added functionality to disable text selection on the body while the sidebar is being resized, enhancing user experience during interactions. - Restored text selection capability once resizing is complete, ensuring normal behavior resumes. * fix: ensure Header component is always rendered in ChatView - Removed conditional rendering of the Header component to ensure it is always displayed, improving the consistency of the chat interface. * refactor: add NewChatButton to ExpandedPanel for improved user interaction - Introduced a NewChatButton component in the ExpandedPanel, allowing users to initiate new conversations easily. - Implemented functionality to clear message cache and invalidate queries upon button click, enhancing performance and user experience. - Restored import statements for OpenSidebar and PresetsMenu in Header component for better organization. --------- Co-authored-by: Danny Avila <danny@librechat.ai>
2026-03-22 06:15:20 +01:00
className="size-9 shrink-0 bg-transparent"
🪄 refactor: UI Polish and Admin Dialog Unification (#11108) * refactor(OpenSidebar): removed useless classNames * style(Header): update hover styles across various components for improved UI consistency * style(Nav): update hover styles in AccountSettings and SearchBar for improved UI consistency * style: update button classes for consistent hover effects and improved UI responsiveness * style(Nav, OpenSidebar, Header, Convo): improve UI responsiveness and animation transitions * style(PresetsMenu, NewChat): update icon sizes and improve component styling for better UI consistency * style(Nav, Root): enhance sidebar mobile animations and responsiveness for better UI experience * style(ExportAndShareMenu, BookmarkMenu): update icon sizes for improved UI consistency * style: remove transition duration from button classes for improved UI responsiveness * style(CustomMenu, ModelSelector): update background colors for improved UI consistency and responsiveness * style(ExportAndShareMenu): update icon color for improved UI consistency * style(TemporaryChat): refine button styles for improved UI consistency and responsiveness * style(BookmarkNav): refactor to use DropdownPopup and remove BookmarkNavItems for improved UI consistency and functionality * style(CustomMenu, EndpointItem): enhance UI elements for improved consistency and accessibility * style(EndpointItem): adjust gap in icon container for improved layout consistency * style(CustomMenu, EndpointItem): update focus ring color for improved UI consistency * style(EndpointItem): update icon color for improved UI consistency in dark theme * style: update focus styles for improved accessibility and consistency across components * refactor(Nav): extract sidebar width to NAV_WIDTH constant Centralize mobile (320px) and desktop (260px) sidebar widths in a single exported constant to avoid magic numbers and ensure consistency. * fix(BookmarkNav): memoize handlers used in useMemo Wrap handleTagClick and handleClear in useCallback and add them to the dropdownItems useMemo dependency array to prevent stale closures. * feat: introduce FilterInput component and replace existing inputs with it across multiple components * feat(DataTable): replace custom input with FilterInput component for improved filtering * fix: Nested dialog overlay stacking issue Fixes overlay appearing behind content when opening nested dialogs. Introduced dynamic z-index calculation based on dialog depth using React context. - First dialog: overlay z-50, content z-100 - Nested dialogs increment by 60: overlay z-110/content z-160, etc. Preserves a11y escape key handling from #10975 and #10851. Regression from #11008 (afb67fcf1) which increased content z-index without adjusting overlay z-index for nested dialog scenarios. * Refactor admin settings components to use a unified AdminSettingsDialog - Removed redundant code from AdminSettings, MCPAdminSettings, and Memories AdminSettings components. - Introduced AdminSettingsDialog component to handle permission management for different sections. - Updated permission handling logic to use a consistent structure across components. - Enhanced role selection and permission confirmation features in the new dialog. - Improved UI consistency and maintainability by centralizing dialog functionality. * refactor(Memory): memory management UI components and replace MemoryViewer with MemoryPanel * refactor(Memory): enhance UI components for Memory dialogs and improve input styling * refactor(Bookmarks): improve bookmark management UI with enhanced styling * refactor(translations): remove redundant filter input and bookmark count entries * refactor(Convo): integrate useShiftKey hook for enhanced keyboard interaction and improve UI responsiveness
2025-12-28 17:01:25 +01:00
aria-label={localize('com_ui_create_memory')}
onClick={() => setCreateDialogOpen(true)}
>
<Plus className="size-4" aria-hidden="true" />
</Button>
}
/>
</OGDialogTrigger>
</MemoryCreateDialog>
)}
</div>
{/* Controls: Usage Badge + Memory Toggle */}
{(memData?.tokenLimit != null || hasOptOutAccess) && (
<div className="flex items-center justify-between">
{/* Usage Badge */}
{memData?.tokenLimit != null && (
<MemoryUsageBadge
percentage={memData.usagePercentage ?? 0}
tokenLimit={memData.tokenLimit}
totalTokens={memData.totalTokens}
/>
)}
{/* Memory Toggle */}
{hasOptOutAccess && (
🎨 refactor: Redesign Sidebar with Unified Icon Strip Layout (#12013) * fix: Graceful SidePanelContext handling when ChatContext unavailable The UnifiedSidebar component is rendered at the Root level before ChatContext is provided (which happens only in ChatRoute). This caused an error when useSidePanelContext tried to call useChatContext before it was available. Changes: - Made SidePanelProvider gracefully handle missing ChatContext with try/catch - Changed useSidePanelContext to return a safe default instead of throwing - Prevents render error on application load and improves robustness * fix: Provide default context value for ChatContext to prevent setFilesLoading errors The ChatContext was initialized with an empty object as default, causing 'setFilesLoading is not a function' errors when components tried to call functions from the context. This fix provides a proper default context with no-op functions for all expected properties. Fixes FileRow component errors that occurred when navigating to sections with file upload functionality (Agent Builder, Attach Files, etc.). * fix: Move ChatFormProvider to Root to fix Prompts sidebar rendering The ChatFormProvider was only wrapping ChatView, but the sidebar (including Prompts) renders separately and needs access to the ChatFormContext. ChatGroupItem uses useSubmitMessage which calls useChatFormContext, causing a React error when Prompts were accessed. This fix moves the ChatFormProvider to the Root component to wrap both the sidebar and the main chat view, ensuring the form context is available throughout the entire application. * fix: Active section switching and dead code cleanup Sync ActivePanelProvider state when defaultActive prop changes so clicking a collapsed-bar icon actually switches the expanded section. Remove the now-unused hideSidePanel atom and its Settings toggle. * style: Redesign sidebar layout with optimized spacing and positioning - Remove duplicate new chat button from sidebar, keep it in main header - Reposition account settings to bottom of expanded sidebar - Simplify collapsed bar padding and alignment - Clean up unused framer-motion imports from Header - Optimize vertical space usage in expanded panel - Align search bar icon color with sidebar theme * fix: Chat history not showing in sidebar Add h-full to ConversationsSection outer div so it fills the Nav content panel, giving react-virtualized's AutoSizer a measurable height. Change Nav content panel from overflow-y-auto to overflow-hidden since the virtualized list handles its own scrolling. * refactor: Move nav icons to fixed icon strip alongside sidebar toggle Extract section icons from the Nav content panel into the ExpandedPanel icon strip, matching the CollapsedBar layout. Both states now share identical button styling and 50px width, eliminating layout shift on toggle. Nav.tsx simplified to content-only rendering. Set text-text-primary on Nav content for consistent child text color. * refactor: sidebar components and remove unused NewChat component * refactor: streamline sidebar components and introduce NewChat button * refactor: enhance sidebar functionality with expanded state management and improved layout * fix: re-implement sidebar resizing functionality with mouse events * feat: enhance sidebar layout responsiveness on mobile * refactor: remove unused components and streamline sidebar functionality * feat: enhance sidebar behavior with responsive transformations for small screens * feat: add new chat button for small screens with message cache clearing * feat: improve state management in sidebar and marketplace components * feat: enhance scrolling behavior in AgentPanel and Nav components * fix: normalize sidebar panel font sizes and default panel selection Set text-sm as base font size on the shared Nav container so all panels render consistently. Guard against empty localStorage value when restoring the active sidebar panel. * fix: adjust avatar size and class for collapsed state in AccountSettings component * style: adjust padding and class names in Nav, Parameters, and ConversationsSection components * fix: close mobile sidebar on pinned favorite selection * refactor: remove unused key in translation file * fix: Address review findings for unified sidebar - Restore ChatFormProvider per-ChatView to fix multi-conversation input isolation; add separate ChatFormProvider in UnifiedSidebar for Prompts panel access - Add inert attribute on mobile sidebar (when collapsed) and main content (when sidebar overlay is open) to prevent keyboard focus leaking - Replace unsafe `as unknown as TChatContext` cast with null-based context that throws descriptively when used outside a provider - Throttle mousemove resize handler with requestAnimationFrame to prevent React state updates at 120Hz during sidebar drag - Unify active panel state: remove split between activeSection in UnifiedSidebar and internal state in ActivePanelContext; single source of truth with localStorage sync on every write - Delete orphaned SidePanelProvider/useSidePanelContext (no consumers after SidePanel.tsx removal) - Add data-testid="new-chat-button" to NewChat component - Add includeHidePanel option to useSideNavLinks; remove no-op hidePanel callback and post-hoc filter in useUnifiedSidebarLinks - Close sidebar on first mobile visit when localStorage has no prior state - Remove unnecessary min-width/max-width CSS transitions (only width needed) - Remove dead SideNav re-export from SidePanel/index.ts - Remove duplicate aria-label from Sidebar nav element - Fix trailing blank line in mobile.css * style: fix prettier formatting in Root.tsx * fix: Address remaining review findings and re-render isolation - Extract useChatHelpers(0) into SidebarChatProvider child component so Recoil atom subscriptions (streaming tokens, latestMessage, etc.) only re-render the active panel — not the sidebar shell, resize logic, or icon strip (Finding 4) - Fix prompt pre-fill when sidebar form context differs from chat form: useSubmitMessage now reads the actual textarea DOM value via mainTextareaId as fallback for the currentText newline check (Finding 1) - Add id="close-sidebar-button" and data-testid to ExpandedPanel toggle so OpenSidebar focus management works after expand (Finding 10/N3) - Replace Dispatch<SetStateAction<number>> prop with onResizeKeyboard(direction) callback on Sidebar (Finding 13) - Fix first-mobile-visit sidebar flash: atom default now checks window.matchMedia at init time instead of defaulting to true then correcting in a useEffect; removes eslint-disable suppression (N1/N2) - Add tests for ActivePanelContext and ChatContext (Finding 8) * refactor: remove no-op memo from SidebarChatProvider memo(SidebarChatProvider) provided no memoization because its only prop (children) is inline JSX — a new reference on every parent render. The streaming isolation works through Recoil subscription scoping, not memo. Clarified in the JSDoc comment. * fix: add shebang to pre-commit hook for Windows compatibility Git on Windows cannot spawn hook scripts without a shebang line, causing 'cannot spawn .husky/pre-commit: No such file or directory'. * style: fix sidebar panel styling inconsistencies - Remove inner overflow-y-auto from AgentPanel form to eliminate double scrollbars when nested inside Nav.tsx's scroll container - Add consistent padding (px-3 py-2) to Nav.tsx panel container - Remove hardcoded 150px cell widths from Files PanelTable; widen date column from 25% to 35% so dates are no longer cut off - Compact pagination row with flex-wrap and smaller text - Add px-1 padding to Parameters panel for consistency - Change overflow-x-visible to overflow-x-hidden on Files and Bookmarks panels to prevent horizontal overflow * fix: Restore panel styling regressions in unified sidebar - Nav.tsx wrapper: remove extra px-3 padding, add hide-scrollbar class, restore py-1 to match old ResizablePanel wrapper - AgentPanel: restore scrollbar-gutter-stable and mx-1 margin (was px-1) - Parameters/Panel: restore p-3 padding (was px-1 pt-1) - Files/Panel: restore overflow-x-visible (was hidden, clipping content) - Files/PanelTable: restore 75/25 column widths, restore 150px cell width constraints, restore pagination text-sm and gap-2 - Bookmarks/Panel: restore overflow-x-visible * style: initial improvements post-sidenav change * style: update text size in DynamicTextarea for improved readability * style: update FilterPrompts alignment in PromptsAccordion for better layout consistency * style: adjust component heights and padding for consistency across SidePanel elements - Updated height from 40px to 36px in AgentSelect for uniformity - Changed button size class from "bg-transparent" to "size-9" in BookmarkTable, MCPBuilderPanel, and MemoryPanel - Added padding class "py-1.5" in DynamicDropdown for improved spacing - Reduced height from 10 to 9 in DynamicInput and DynamicTags for a cohesive look - Adjusted padding in Parameters/Panel for better layout * style: standardize button sizes and icon dimensions across chat components - Updated button size class from 'size-10' to 'size-9' in multiple components for consistency. - Adjusted icon sizes from 'icon-lg' to 'icon-md' in various locations to maintain uniformity. - Modified header height for better alignment with design specifications. * style: enhance layout consistency and component structure across various panels - Updated ActivePanelContext to utilize useCallback and useMemo for improved performance. - Adjusted padding and layout in multiple SidePanel components for better visual alignment. - Standardized icon sizes and button dimensions in AddMultiConvo and other components. - Improved overall spacing and structure in PromptsAccordion, MemoryPanel, and FilesPanel for a cohesive design. * style: standardize component heights and text sizes across various panels - Adjusted button heights from 10px to 9px in multiple components for consistency. - Updated text sizes from 'text-sm' to 'text-xs' in DynamicCheckbox, DynamicCombobox, DynamicDropdown, DynamicInput, DynamicSlider, DynamicSwitch, DynamicTags, and DynamicTextarea for improved readability. - Added portal prop to account settings menu for better rendering behavior. * refactor: optimize Tooltip component structure for performance - Introduced a new memoized TooltipPopup component to prevent unnecessary re-renders of the TooltipAnchor when the tooltip mounts/unmounts. - Updated TooltipAnchor to utilize the new TooltipPopup, improving separation of concerns and enhancing performance. - Maintained existing functionality while improving code clarity and maintainability. * refactor: improve sidebar transition handling for better responsiveness - Enhanced the transition properties in the UnifiedSidebar component to include min-width and max-width adjustments, ensuring smoother resizing behavior. - Cleaned up import statements by removing unnecessary lines for better code clarity. * fix: prevent text selection during sidebar resizing - Added functionality to disable text selection on the body while the sidebar is being resized, enhancing user experience during interactions. - Restored text selection capability once resizing is complete, ensuring normal behavior resumes. * fix: ensure Header component is always rendered in ChatView - Removed conditional rendering of the Header component to ensure it is always displayed, improving the consistency of the chat interface. * refactor: add NewChatButton to ExpandedPanel for improved user interaction - Introduced a NewChatButton component in the ExpandedPanel, allowing users to initiate new conversations easily. - Implemented functionality to clear message cache and invalidate queries upon button click, enhancing performance and user experience. - Restored import statements for OpenSidebar and PresetsMenu in Header component for better organization. --------- Co-authored-by: Danny Avila <danny@librechat.ai>
2026-03-22 06:15:20 +01:00
<div className="ml-auto flex items-center gap-2 text-xs">
🪄 refactor: UI Polish and Admin Dialog Unification (#11108) * refactor(OpenSidebar): removed useless classNames * style(Header): update hover styles across various components for improved UI consistency * style(Nav): update hover styles in AccountSettings and SearchBar for improved UI consistency * style: update button classes for consistent hover effects and improved UI responsiveness * style(Nav, OpenSidebar, Header, Convo): improve UI responsiveness and animation transitions * style(PresetsMenu, NewChat): update icon sizes and improve component styling for better UI consistency * style(Nav, Root): enhance sidebar mobile animations and responsiveness for better UI experience * style(ExportAndShareMenu, BookmarkMenu): update icon sizes for improved UI consistency * style: remove transition duration from button classes for improved UI responsiveness * style(CustomMenu, ModelSelector): update background colors for improved UI consistency and responsiveness * style(ExportAndShareMenu): update icon color for improved UI consistency * style(TemporaryChat): refine button styles for improved UI consistency and responsiveness * style(BookmarkNav): refactor to use DropdownPopup and remove BookmarkNavItems for improved UI consistency and functionality * style(CustomMenu, EndpointItem): enhance UI elements for improved consistency and accessibility * style(EndpointItem): adjust gap in icon container for improved layout consistency * style(CustomMenu, EndpointItem): update focus ring color for improved UI consistency * style(EndpointItem): update icon color for improved UI consistency in dark theme * style: update focus styles for improved accessibility and consistency across components * refactor(Nav): extract sidebar width to NAV_WIDTH constant Centralize mobile (320px) and desktop (260px) sidebar widths in a single exported constant to avoid magic numbers and ensure consistency. * fix(BookmarkNav): memoize handlers used in useMemo Wrap handleTagClick and handleClear in useCallback and add them to the dropdownItems useMemo dependency array to prevent stale closures. * feat: introduce FilterInput component and replace existing inputs with it across multiple components * feat(DataTable): replace custom input with FilterInput component for improved filtering * fix: Nested dialog overlay stacking issue Fixes overlay appearing behind content when opening nested dialogs. Introduced dynamic z-index calculation based on dialog depth using React context. - First dialog: overlay z-50, content z-100 - Nested dialogs increment by 60: overlay z-110/content z-160, etc. Preserves a11y escape key handling from #10975 and #10851. Regression from #11008 (afb67fcf1) which increased content z-index without adjusting overlay z-index for nested dialog scenarios. * Refactor admin settings components to use a unified AdminSettingsDialog - Removed redundant code from AdminSettings, MCPAdminSettings, and Memories AdminSettings components. - Introduced AdminSettingsDialog component to handle permission management for different sections. - Updated permission handling logic to use a consistent structure across components. - Enhanced role selection and permission confirmation features in the new dialog. - Improved UI consistency and maintainability by centralizing dialog functionality. * refactor(Memory): memory management UI components and replace MemoryViewer with MemoryPanel * refactor(Memory): enhance UI components for Memory dialogs and improve input styling * refactor(Bookmarks): improve bookmark management UI with enhanced styling * refactor(translations): remove redundant filter input and bookmark count entries * refactor(Convo): integrate useShiftKey hook for enhanced keyboard interaction and improve UI responsiveness
2025-12-28 17:01:25 +01:00
<span className="text-text-secondary">{localize('com_ui_use_memory')}</span>
<Switch
checked={referenceSavedMemories}
onCheckedChange={handleMemoryToggle}
aria-label={localize('com_ui_use_memory')}
disabled={updateMemoryPreferencesMutation.isLoading}
/>
</div>
)}
</div>
)}
{/* Memory List */}
<MemoryList
memories={currentRows}
hasUpdateAccess={hasUpdateAccess}
isFiltered={searchQuery.length > 0}
/>
{/* Footer: Admin Settings + Pagination */}
{(user?.role === SystemRoles.ADMIN || filteredMemories.length > pageSize) && (
<div className="flex items-center justify-between gap-2">
{/* Admin Settings - Left */}
{user?.role === SystemRoles.ADMIN ? <AdminSettings /> : <div />}
{/* Pagination - Right */}
{filteredMemories.length > pageSize && (
<div className="flex items-center gap-2" role="navigation" aria-label="Pagination">
<Button
variant="outline"
size="sm"
onClick={() => setPageIndex((prev) => Math.max(prev - 1, 0))}
disabled={pageIndex === 0}
aria-label={localize('com_ui_prev')}
>
{localize('com_ui_prev')}
</Button>
<div className="whitespace-nowrap text-sm" aria-live="polite">
{pageIndex + 1} / {totalPages}
</div>
<Button
variant="outline"
size="sm"
onClick={() => setPageIndex((prev) => (prev + 1 < totalPages ? prev + 1 : prev))}
disabled={pageIndex + 1 >= totalPages}
aria-label={localize('com_ui_next')}
>
{localize('com_ui_next')}
</Button>
</div>
)}
</div>
)}
</div>
</div>
);
}