LibreChat/client/src/routes/Root.tsx
Danny Avila b2f44fc90f
🧩 feat: Web Search Config Validations & Clipboard Citation Processing (#7530)
* 🔧 chore: Add missing optional `scraperTimeout` to webSearchSchema

* chore: Add missing optional `scraperTimeout` to web search authentication result

* chore: linting

* feat: Integrate attachment handling and citation processing in message components

- Added `useAttachments` hook to manage message attachments and search results.
- Updated `MessageParts`, `ContentParts`, and `ContentRender` components to utilize the new hook for improved attachment handling.
- Enhanced `useCopyToClipboard` to format citations correctly, including support for composite citations and deduplication.
- Introduced utility functions for citation processing and cleanup.
- Added tests for the new `useCopyToClipboard` functionality to ensure proper citation formatting and handling.

* feat: Add configuration for LibreChat Code Interpreter API and Web Search variables

* fix: Update searchResults type to use SearchResultData for better type safety

* feat: Add web search configuration validation and logging

- Introduced `checkWebSearchConfig` function to validate web search configuration values, ensuring they are environment variable references.
- Added logging for proper configuration and warnings for incorrect values.
- Created unit tests for `checkWebSearchConfig` to cover various scenarios, including valid and invalid configurations.

* docs: Update README to include Web Search feature details

- Added a section for the Web Search feature, highlighting its capabilities to search the internet and enhance AI context.
- Included links for further information on the Web Search functionality.

* ci: Add mock for checkWebSearchConfig in AppService tests

* chore: linting

* feat: Enhance Shared Messages with Web Search UI by adding searchResults prop to SearchContent and MinimalHoverButtons components

* chore: linting

* refactor: remove Meilisearch index sync from importConversations function

* feat: update safeSearch implementation to use SafeSearchTypes enum

* refactor: remove commented-out code in loadTools function

* fix: ensure responseMessageId handles latestMessage ID correctly

* feat: enhance Vite configuration for improved chunking and caching

- Added additional globIgnores for map files in Workbox configuration.
- Implemented high-impact chunking for various large libraries to optimize performance.
- Increased chunkSizeWarningLimit from 1200 to 1500 for better handling of larger chunks.

* refactor: move health check hook to Root, fix bad setState for Temporary state

- Enhanced the `useHealthCheck` hook to initiate health checks only when the user is authenticated.
- Added logic for managing health check intervals and handling window focus events.
- Introduced a new test suite for `useHealthCheck` to cover various scenarios including authentication state changes and error handling.
- Removed the health check invocation from `ChatRoute` and added it to `Root` for global health monitoring.

* fix: update font alias in Vite configuration for correct path resolution
2025-05-24 10:23:17 -04:00

96 lines
3.2 KiB
TypeScript

import React, { useState, useEffect } from 'react';
import { Outlet } from 'react-router-dom';
import type { ContextType } from '~/common';
import {
useAuthContext,
useAssistantsMap,
useAgentsMap,
useFileMap,
useSearchEnabled,
} from '~/hooks';
import {
AgentsMapContext,
AssistantsMapContext,
FileMapContext,
SetConvoProvider,
} from '~/Providers';
import TermsAndConditionsModal from '~/components/ui/TermsAndConditionsModal';
import { useUserTermsQuery, useGetStartupConfig } from '~/data-provider';
import { Nav, MobileNav } from '~/components/Nav';
import { useHealthCheck } from '~/data-provider';
import { Banner } from '~/components/Banners';
export default function Root() {
const [showTerms, setShowTerms] = useState(false);
const [bannerHeight, setBannerHeight] = useState(0);
const [navVisible, setNavVisible] = useState(() => {
const savedNavVisible = localStorage.getItem('navVisible');
return savedNavVisible !== null ? JSON.parse(savedNavVisible) : true;
});
const { isAuthenticated, logout } = useAuthContext();
// Global health check - runs once per authenticated session
useHealthCheck(isAuthenticated);
const assistantsMap = useAssistantsMap({ isAuthenticated });
const agentsMap = useAgentsMap({ isAuthenticated });
const fileMap = useFileMap({ isAuthenticated });
const { data: config } = useGetStartupConfig();
const { data: termsData } = useUserTermsQuery({
enabled: isAuthenticated && config?.interface?.termsOfService?.modalAcceptance === true,
});
useSearchEnabled(isAuthenticated);
useEffect(() => {
if (termsData) {
setShowTerms(!termsData.termsAccepted);
}
}, [termsData]);
const handleAcceptTerms = () => {
setShowTerms(false);
};
const handleDeclineTerms = () => {
setShowTerms(false);
logout('/login?redirect=false');
};
if (!isAuthenticated) {
return null;
}
return (
<SetConvoProvider>
<FileMapContext.Provider value={fileMap}>
<AssistantsMapContext.Provider value={assistantsMap}>
<AgentsMapContext.Provider value={agentsMap}>
<Banner onHeightChange={setBannerHeight} />
<div className="flex" style={{ height: `calc(100dvh - ${bannerHeight}px)` }}>
<div className="relative z-0 flex h-full w-full overflow-hidden">
<Nav navVisible={navVisible} setNavVisible={setNavVisible} />
<div className="relative flex h-full max-w-full flex-1 flex-col overflow-hidden">
<MobileNav setNavVisible={setNavVisible} />
<Outlet context={{ navVisible, setNavVisible } satisfies ContextType} />
</div>
</div>
</div>
</AgentsMapContext.Provider>
{config?.interface?.termsOfService?.modalAcceptance === true && (
<TermsAndConditionsModal
open={showTerms}
onOpenChange={setShowTerms}
onAccept={handleAcceptTerms}
onDecline={handleDeclineTerms}
title={config.interface.termsOfService.modalTitle}
modalContent={config.interface.termsOfService.modalContent}
/>
)}
</AssistantsMapContext.Provider>
</FileMapContext.Provider>
</SetConvoProvider>
);
}