Merge remote-tracking branch 'origin/main' into feat/auto-failover-switch

# Conflicts:
#	src/App.tsx
This commit is contained in:
YoVinchen
2025-12-22 17:23:41 +08:00
2 changed files with 95 additions and 77 deletions
+89 -75
View File
@@ -310,79 +310,93 @@ function App() {
}; };
const renderContent = () => { const renderContent = () => {
switch (currentView) { const content = (() => {
case "settings": switch (currentView) {
return ( case "settings":
<SettingsPage return (
open={true} <SettingsPage
onOpenChange={() => setCurrentView("providers")} open={true}
onImportSuccess={handleImportSuccess} onOpenChange={() => setCurrentView("providers")}
/> onImportSuccess={handleImportSuccess}
); />
case "prompts": );
return ( case "prompts":
<PromptPanel return (
ref={promptPanelRef} <PromptPanel
open={true} ref={promptPanelRef}
onOpenChange={() => setCurrentView("providers")} open={true}
appId={activeApp} onOpenChange={() => setCurrentView("providers")}
/> appId={activeApp}
); />
case "skills": );
return ( case "skills":
<SkillsPage return (
ref={skillsPageRef} <SkillsPage
onClose={() => setCurrentView("providers")} ref={skillsPageRef}
initialApp={activeApp} onClose={() => setCurrentView("providers")}
/> initialApp={activeApp}
); />
case "mcp": );
return ( case "mcp":
<UnifiedMcpPanel return (
ref={mcpPanelRef} <UnifiedMcpPanel
onOpenChange={() => setCurrentView("providers")} ref={mcpPanelRef}
/> onOpenChange={() => setCurrentView("providers")}
); />
case "agents": );
return <AgentsPanel onOpenChange={() => setCurrentView("providers")} />; case "agents":
default: return <AgentsPanel onOpenChange={() => setCurrentView("providers")} />;
return ( default:
<div className="mx-auto max-w-[56rem] px-5 flex flex-col h-[calc(100vh-8rem)] overflow-hidden"> return (
{/* 独立滚动容器 - 解决 Linux/Ubuntu 下 DndContext 与滚轮事件冲突 */} <div className="mx-auto max-w-[56rem] px-5 flex flex-col h-[calc(100vh-8rem)] overflow-hidden">
<div className="flex-1 px-1 pb-12 overflow-x-hidden overflow-y-auto"> {/* 独立滚动容器 - 解决 Linux/Ubuntu 下 DndContext 与滚轮事件冲突 */}
<AnimatePresence mode="wait"> <div className="flex-1 overflow-y-auto overflow-x-hidden pb-12 px-1">
<motion.div <AnimatePresence mode="wait">
key={activeApp} <motion.div
initial={{ opacity: 0 }} key={activeApp}
animate={{ opacity: 1 }} initial={{ opacity: 0 }}
exit={{ opacity: 0 }} animate={{ opacity: 1 }}
transition={{ duration: 0.15 }} exit={{ opacity: 0 }}
className="space-y-4" transition={{ duration: 0.15 }}
> className="space-y-4"
<ProviderList >
providers={providers} <ProviderList
currentProviderId={currentProviderId} providers={providers}
appId={activeApp} currentProviderId={currentProviderId}
isLoading={isLoading} appId={activeApp}
isProxyRunning={isProxyRunning} isLoading={isLoading}
isProxyTakeover={ isProxyRunning={isProxyRunning}
isProxyRunning && isCurrentAppTakeoverActive isProxyTakeover={isProxyRunning && isCurrentAppTakeoverActive}
} activeProviderId={activeProviderId}
activeProviderId={activeProviderId} onSwitch={switchProvider}
onSwitch={switchProvider} onEdit={setEditingProvider}
onEdit={setEditingProvider} onDelete={setConfirmDelete}
onDelete={setConfirmDelete} onDuplicate={handleDuplicateProvider}
onDuplicate={handleDuplicateProvider} onConfigureUsage={setUsageProvider}
onConfigureUsage={setUsageProvider} onOpenWebsite={handleOpenWebsite}
onOpenWebsite={handleOpenWebsite} onCreate={() => setIsAddOpen(true)}
onCreate={() => setIsAddOpen(true)} />
/> </motion.div>
</motion.div> </AnimatePresence>
</AnimatePresence> </div>
</div> </div>
</div> );
); }
} })();
return (
<AnimatePresence mode="wait">
<motion.div
key={currentView}
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
transition={{ duration: 0.2 }}
>
{content}
</motion.div>
</AnimatePresence>
);
}; };
return ( return (
@@ -494,14 +508,14 @@ function App() {
</div> </div>
<div <div
className="flex items-center gap-2" className="flex items-center gap-2 min-h-[40px]"
style={{ WebkitAppRegion: "no-drag" } as any} style={{ WebkitAppRegion: "no-drag" } as any}
> >
{currentView === "prompts" && ( {currentView === "prompts" && (
<Button <Button
size="icon" size="icon"
onClick={() => promptPanelRef.current?.openAdd()} onClick={() => promptPanelRef.current?.openAdd()}
className={addActionButtonClass} className={`ml-auto ${addActionButtonClass}`}
title={t("prompts.add")} title={t("prompts.add")}
> >
<Plus className="w-5 h-5" /> <Plus className="w-5 h-5" />
@@ -511,7 +525,7 @@ function App() {
<Button <Button
size="icon" size="icon"
onClick={() => mcpPanelRef.current?.openAdd()} onClick={() => mcpPanelRef.current?.openAdd()}
className={addActionButtonClass} className={`ml-auto ${addActionButtonClass}`}
title={t("mcp.unifiedPanel.addServer")} title={t("mcp.unifiedPanel.addServer")}
> >
<Plus className="w-5 h-5" /> <Plus className="w-5 h-5" />
+6 -2
View File
@@ -1,5 +1,6 @@
import React from "react"; import React from "react";
import { createPortal } from "react-dom"; import { createPortal } from "react-dom";
import { motion } from "framer-motion";
import { ArrowLeft } from "lucide-react"; import { ArrowLeft } from "lucide-react";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
@@ -35,7 +36,10 @@ export const FullScreenPanel: React.FC<FullScreenPanelProps> = ({
if (!isOpen) return null; if (!isOpen) return null;
return createPortal( return createPortal(
<div <motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 0.2 }}
className="fixed inset-0 z-[60] flex flex-col" className="fixed inset-0 z-[60] flex flex-col"
style={{ backgroundColor: "hsl(var(--background))" }} style={{ backgroundColor: "hsl(var(--background))" }}
> >
@@ -71,7 +75,7 @@ export const FullScreenPanel: React.FC<FullScreenPanelProps> = ({
</div> </div>
</div> </div>
)} )}
</div>, </motion.div>,
document.body, document.body,
); );
}; };