Ver Fonte

修复AI会话和大纲会话历史记录无法打开的问题

Mochocyang há 3 meses atrás
pai
commit
9825c38435

+ 7 - 1
src/components/chat/chat-panel.tsx

@@ -432,6 +432,7 @@ function ConversationTabs({ onAbortStream }: { onAbortStream: (convId: string) =
   const [historyOpen, setHistoryOpen] = useState(false)
   const historyRef = useRef<HTMLDivElement | null>(null)
   const historyButtonRef = useRef<HTMLButtonElement | null>(null)
+  const historyDropdownRef = useRef<HTMLDivElement | null>(null)
   const [historyDropdownStyle, setHistoryDropdownStyle] = useState<CSSProperties | null>(null)
 
   const isStreamingConversation = (convId: string) => convId in streamingContents
@@ -446,7 +447,11 @@ function ConversationTabs({ onAbortStream }: { onAbortStream: (convId: string) =
   useEffect(() => {
     if (!historyOpen) return
     function handleClick(event: MouseEvent) {
-      if (historyRef.current && !historyRef.current.contains(event.target as Node)) {
+      const target = event.target as Node
+      if (
+        historyRef.current && !historyRef.current.contains(target) &&
+        historyDropdownRef.current && !historyDropdownRef.current.contains(target)
+      ) {
         setHistoryOpen(false)
       }
     }
@@ -623,6 +628,7 @@ function ConversationTabs({ onAbortStream }: { onAbortStream: (convId: string) =
           {historyOpen && historyDropdownStyle &&
             createPortal(
               <div
+                ref={historyDropdownRef}
                 className="fixed z-50 max-h-[60vh] w-72 overflow-y-auto rounded-md border border-border bg-background p-1 shadow-lg"
                 style={historyDropdownStyle}
               >

+ 17 - 40
src/components/sources/outline-action-toolbar.tsx

@@ -1,8 +1,7 @@
 import { useCallback, useState } from "react"
-import { Loader2, MessageSquare, Sparkles } from "lucide-react"
+import { Loader2, MessageSquare } from "lucide-react"
 import { useTranslation } from "react-i18next"
 import { Button } from "@/components/ui/button"
-import { OutlineGeneratorDialog, type OutlineGeneratorMode } from "@/components/sources/outline-generator-dialog"
 import { runBulkOutlineIngest, formatBulkOutlineIngestResult, OutlineIngestNotReadyError } from "@/lib/novel/outline-generation"
 import { cn } from "@/lib/utils"
 import { toast } from "@/lib/toast"
@@ -25,8 +24,6 @@ export function OutlineActionToolbar({
   const project = useWikiStore((s) => s.project)
   const setActiveView = useWikiStore((s) => s.setActiveView)
   const setOutlineChatOpen = useOutlineGenerationStore((s) => s.setPanelOpen)
-  const [outlineDialogOpen, setOutlineDialogOpen] = useState(false)
-  const [outlineDialogMode, setOutlineDialogMode] = useState<OutlineGeneratorMode>("outline")
   const [bulkIngestRunning, setBulkIngestRunning] = useState(false)
 
   const bulkOutlineProgressRunning = useImportProgressStore((s) => (
@@ -39,11 +36,6 @@ export function OutlineActionToolbar({
 
   const bulkIngestActive = bulkIngestRunning || bulkOutlineProgressRunning
 
-  function openOutlineDialog(mode: OutlineGeneratorMode) {
-    setOutlineDialogMode(mode)
-    setOutlineDialogOpen(true)
-  }
-
   const handleOpenOutlineChat = useCallback(() => {
     if (onToggleOutlineChat) {
       onToggleOutlineChat()
@@ -74,36 +66,21 @@ export function OutlineActionToolbar({
   }, [bulkIngestActive, onBulkIngestResult, project, t])
 
   return (
-    <>
-      <div className={cn("flex flex-wrap gap-1", className)}>
-        <Button size="sm" onClick={() => openOutlineDialog("outline")}>
-          <Sparkles className="mr-1 h-4 w-4" />
-          {t("novel.outlineGenerator.title")}
-        </Button>
-        <Button size="sm" variant="outline" onClick={handleOpenOutlineChat}>
-          <MessageSquare className="mr-1 h-4 w-4" />
-          AI大纲
-        </Button>
-        <Button size="sm" variant="outline" onClick={() => openOutlineDialog("refine")}>
-          {t("novel.outlineGenerator.refineTitle")}
-        </Button>
-        <Button size="sm" variant="outline" onClick={() => void handleBulkIngest()} disabled={bulkIngestActive}>
-          {bulkIngestActive ? (
-            <>
-              <Loader2 className="mr-1 h-4 w-4 animate-spin" />
-              {t("novel.outlineGenerator.bulkIngesting")}
-            </>
-          ) : (
-            t("novel.outlineGenerator.bulkIngest")
-          )}
-        </Button>
-      </div>
-
-      <OutlineGeneratorDialog
-        open={outlineDialogOpen}
-        onOpenChange={setOutlineDialogOpen}
-        mode={outlineDialogMode}
-      />
-    </>
+    <div className={cn("flex flex-wrap gap-1", className)}>
+      <Button size="sm" variant="outline" onClick={handleOpenOutlineChat}>
+        <MessageSquare className="mr-1 h-4 w-4" />
+        AI大纲
+      </Button>
+      <Button size="sm" variant="outline" onClick={() => void handleBulkIngest()} disabled={bulkIngestActive}>
+        {bulkIngestActive ? (
+          <>
+            <Loader2 className="mr-1 h-4 w-4 animate-spin" />
+            {t("novel.outlineGenerator.bulkIngesting")}
+          </>
+        ) : (
+          t("novel.outlineGenerator.bulkIngest")
+        )}
+      </Button>
+    </div>
   )
 }

+ 7 - 1
src/components/sources/outline-chat-panel.tsx

@@ -920,6 +920,7 @@ export function OutlineChatPanel({ onClose }: { onClose: () => void }) {
   const [historyOpen, setHistoryOpen] = useState(false);
   const historyRef = useRef<HTMLDivElement | null>(null);
   const historyButtonRef = useRef<HTMLButtonElement | null>(null);
+  const historyDropdownRef = useRef<HTMLDivElement | null>(null);
   const [historyDropdownStyle, setHistoryDropdownStyle] = useState<CSSProperties | null>(null);
   const [deAiSkillConfig, setDeAiSkillConfig] = useState<DeAiSkillConfig | null>(null);
   const [writingSkills, setWritingSkills] = useState<UserSkill[]>([]);
@@ -1011,7 +1012,11 @@ export function OutlineChatPanel({ onClose }: { onClose: () => void }) {
   useEffect(() => {
     if (!historyOpen) return;
     function handleClick(event: MouseEvent) {
-      if (historyRef.current && !historyRef.current.contains(event.target as Node)) {
+      const target = event.target as Node;
+      if (
+        historyRef.current && !historyRef.current.contains(target) &&
+        historyDropdownRef.current && !historyDropdownRef.current.contains(target)
+      ) {
         setHistoryOpen(false);
       }
     }
@@ -2389,6 +2394,7 @@ export function OutlineChatPanel({ onClose }: { onClose: () => void }) {
           {historyOpen && historyDropdownStyle
             ? createPortal(
                 <div
+                  ref={historyDropdownRef}
                   className="fixed z-50 max-h-[60vh] w-72 overflow-y-auto rounded-md border border-border bg-background p-1 shadow-lg"
                   style={historyDropdownStyle}
                 >