chore: add missing SidePanelProvider for AgentMarketplace and organize imports

This commit is contained in:
Danny Avila 2025-07-18 12:02:38 -04:00
parent 04af67951b
commit 5ca9da378b
No known key found for this signature in database
GPG key ID: BF31EEB2C5CA0956

View file

@ -1,25 +1,24 @@
import React, { useState, useEffect, useMemo } from 'react'; import React, { useState, useEffect, useMemo } from 'react';
import { useOutletContext } from 'react-router-dom'; import { useOutletContext } from 'react-router-dom';
import { useSearchParams, useParams, useNavigate } from 'react-router-dom';
import { useSetRecoilState, useRecoilValue } from 'recoil'; import { useSetRecoilState, useRecoilValue } from 'recoil';
import { PermissionTypes, Permissions } from 'librechat-data-provider';
import { useSearchParams, useParams, useNavigate } from 'react-router-dom';
import type t from 'librechat-data-provider'; import type t from 'librechat-data-provider';
import type { ContextType } from '~/common'; import type { ContextType } from '~/common';
import { useGetEndpointsQuery, useGetAgentCategoriesQuery } from '~/data-provider'; import { useGetEndpointsQuery, useGetAgentCategoriesQuery } from '~/data-provider';
import { useDocumentTitle, useHasAccess } from '~/hooks';
import useLocalize from '~/hooks/useLocalize';
import { TooltipAnchor, Button } from '~/components/ui';
import { NewChatIcon } from '~/components/svg';
import { OpenSidebar } from '~/components/Chat/Menus';
import { SidePanelGroup } from '~/components/SidePanel';
import { MarketplaceProvider } from './MarketplaceContext'; import { MarketplaceProvider } from './MarketplaceContext';
import { useDocumentTitle, useHasAccess } from '~/hooks';
import { TooltipAnchor, Button } from '~/components/ui';
import { SidePanelGroup } from '~/components/SidePanel';
import { OpenSidebar } from '~/components/Chat/Menus';
import { SidePanelProvider } from '~/Providers';
import { NewChatIcon } from '~/components/svg';
import useLocalize from '~/hooks/useLocalize';
import CategoryTabs from './CategoryTabs'; import CategoryTabs from './CategoryTabs';
import AgentDetail from './AgentDetail'; import AgentDetail from './AgentDetail';
import SearchBar from './SearchBar'; import SearchBar from './SearchBar';
import AgentGrid from './AgentGrid'; import AgentGrid from './AgentGrid';
import store from '~/store'; import store from '~/store';
import { PermissionTypes, Permissions } from 'librechat-data-provider';
interface AgentMarketplaceProps { interface AgentMarketplaceProps {
className?: string; className?: string;
@ -191,128 +190,132 @@ const AgentMarketplace: React.FC<AgentMarketplaceProps> = ({ className = '' }) =
return ( return (
<div className={`relative flex w-full grow overflow-hidden bg-presentation ${className}`}> <div className={`relative flex w-full grow overflow-hidden bg-presentation ${className}`}>
<MarketplaceProvider> <MarketplaceProvider>
<SidePanelGroup <SidePanelProvider>
defaultLayout={defaultLayout} <SidePanelGroup
fullPanelCollapse={fullCollapse} defaultLayout={defaultLayout}
defaultCollapsed={defaultCollapsed} fullPanelCollapse={fullCollapse}
> defaultCollapsed={defaultCollapsed}
<main className="flex h-full flex-col overflow-y-auto" role="main"> >
{/* Simplified header for agents marketplace - only show nav controls when needed */} <main className="flex h-full flex-col overflow-y-auto" role="main">
<div className="sticky top-0 z-10 flex h-14 w-full items-center justify-between bg-white p-2 font-semibold text-text-primary dark:bg-gray-800"> {/* Simplified header for agents marketplace - only show nav controls when needed */}
<div className="mx-1 flex items-center gap-2"> <div className="sticky top-0 z-10 flex h-14 w-full items-center justify-between bg-white p-2 font-semibold text-text-primary dark:bg-gray-800">
{!navVisible && <OpenSidebar setNavVisible={setNavVisible} />} <div className="mx-1 flex items-center gap-2">
{!navVisible && ( {!navVisible && <OpenSidebar setNavVisible={setNavVisible} />}
<TooltipAnchor {!navVisible && (
description={localize('com_ui_new_chat')} <TooltipAnchor
render={ description={localize('com_ui_new_chat')}
<Button render={
size="icon" <Button
variant="outline" size="icon"
data-testid="agents-new-chat-button" variant="outline"
aria-label={localize('com_ui_new_chat')} data-testid="agents-new-chat-button"
className="rounded-xl border border-border-light bg-surface-secondary p-2 hover:bg-surface-hover max-md:hidden" aria-label={localize('com_ui_new_chat')}
onClick={handleNewChat} className="rounded-xl border border-border-light bg-surface-secondary p-2 hover:bg-surface-hover max-md:hidden"
> onClick={handleNewChat}
<NewChatIcon /> >
</Button> <NewChatIcon />
} </Button>
/> }
)} />
</div> )}
</div>
<div className="container mx-auto max-w-4xl px-4 py-8">
{/* Hero Section - ChatGPT Style */}
<div className="mb-8 mt-12 text-center">
<h1 className="mb-3 text-5xl font-bold tracking-tight text-gray-900 dark:text-white">
{localize('com_agents_marketplace')}
</h1>
<p className="mx-auto mb-6 max-w-2xl text-lg text-gray-600 dark:text-gray-300">
{localize('com_agents_marketplace_subtitle')}
</p>
{/* Search bar */}
<div className="mx-auto max-w-2xl">
<SearchBar value={searchQuery} onSearch={handleSearch} />
</div> </div>
</div> </div>
<div className="container mx-auto max-w-4xl px-4 py-8">
{/* Hero Section - ChatGPT Style */}
<div className="mb-8 mt-12 text-center">
<h1 className="mb-3 text-5xl font-bold tracking-tight text-gray-900 dark:text-white">
{localize('com_agents_marketplace')}
</h1>
<p className="mx-auto mb-6 max-w-2xl text-lg text-gray-600 dark:text-gray-300">
{localize('com_agents_marketplace_subtitle')}
</p>
{/* Category tabs */} {/* Search bar */}
<CategoryTabs <div className="mx-auto max-w-2xl">
categories={categoriesQuery.data || []} <SearchBar value={searchQuery} onSearch={handleSearch} />
activeTab={activeTab} </div>
isLoading={categoriesQuery.isLoading} </div>
onChange={handleTabChange}
/>
{/* Category header - only show when not searching */} {/* Category tabs */}
{!searchQuery && ( <CategoryTabs
<div className="mb-6"> categories={categoriesQuery.data || []}
{(() => { activeTab={activeTab}
// Get category data for display isLoading={categoriesQuery.isLoading}
const getCategoryData = () => { onChange={handleTabChange}
if (activeTab === 'promoted') { />
{/* Category header - only show when not searching */}
{!searchQuery && (
<div className="mb-6">
{(() => {
// Get category data for display
const getCategoryData = () => {
if (activeTab === 'promoted') {
return {
name: localize('com_agents_top_picks'),
description: localize('com_agents_recommended'),
};
}
if (activeTab === 'all') {
return {
name: 'All Agents',
description: 'Browse all shared agents across all categories',
};
}
// Find the category in the API data
const categoryData = categoriesQuery.data?.find(
(cat) => cat.value === activeTab,
);
if (categoryData) {
return {
name: categoryData.label,
description: categoryData.description || '',
};
}
// Fallback for unknown categories
return { return {
name: localize('com_agents_top_picks'), name: activeTab.charAt(0).toUpperCase() + activeTab.slice(1),
description: localize('com_agents_recommended'), description: '',
}; };
}
if (activeTab === 'all') {
return {
name: 'All Agents',
description: 'Browse all shared agents across all categories',
};
}
// Find the category in the API data
const categoryData = categoriesQuery.data?.find(
(cat) => cat.value === activeTab,
);
if (categoryData) {
return {
name: categoryData.label,
description: categoryData.description || '',
};
}
// Fallback for unknown categories
return {
name: activeTab.charAt(0).toUpperCase() + activeTab.slice(1),
description: '',
}; };
};
const { name, description } = getCategoryData(); const { name, description } = getCategoryData();
return ( return (
<div className="text-left"> <div className="text-left">
<h2 className="text-2xl font-bold text-gray-900 dark:text-white">{name}</h2> <h2 className="text-2xl font-bold text-gray-900 dark:text-white">
{description && ( {name}
<p className="mt-2 text-gray-600 dark:text-gray-300">{description}</p> </h2>
)} {description && (
</div> <p className="mt-2 text-gray-600 dark:text-gray-300">{description}</p>
); )}
})()} </div>
</div> );
})()}
</div>
)}
{/* Agent grid */}
<AgentGrid
category={activeTab}
searchQuery={searchQuery}
onSelectAgent={handleAgentSelect}
/>
</div>
{/* Agent detail dialog */}
{isDetailOpen && selectedAgent && (
<AgentDetail
agent={selectedAgent}
isOpen={isDetailOpen}
onClose={handleDetailClose}
/>
)} )}
</main>
{/* Agent grid */} </SidePanelGroup>
<AgentGrid </SidePanelProvider>
category={activeTab}
searchQuery={searchQuery}
onSelectAgent={handleAgentSelect}
/>
</div>
{/* Agent detail dialog */}
{isDetailOpen && selectedAgent && (
<AgentDetail
agent={selectedAgent}
isOpen={isDetailOpen}
onClose={handleDetailClose}
/>
)}
</main>
</SidePanelGroup>
</MarketplaceProvider> </MarketplaceProvider>
</div> </div>
); );