fix(production-readiness): 3-batch production readiness cleanup — 12 tasks
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled

Batch 1 — User-facing fixes:
- B1-1: Pipeline verified end-to-end (14 Rust commands, 8 frontend invoke, fully connected)
- B1-2: MessageSearch restored to ChatArea with search button in DeerFlow header
- B1-3: Viking cleanup — removed 5 orphan invokes (no Rust impl), added addWithMetadata + storeWithSummaries methods + summary generation UI
- B1-4: api-fallbacks transparency — added _isFallback markers + console.warn to all 6 fallback functions

Batch 2 — System health:
- B2-1: Document drift calibration — TRUTH.md/README.md numbers verified and updated
- B2-2: @reserved annotations on 15 SaaS handler functions with no frontend callers
- B2-3: Scheduled Task Admin V2 — new service + page + route + sidebar navigation
- B2-4: TRUTH.md Pipeline/Viking/ScheduledTask records corrected

Batch 3 — Long-term quality:
- B3-1: hand_run_status/hand_run_list verified as fully implemented (not stubs)
- B3-2: Identity snapshot rollback UI added to RightPanel
- B3-3: P2 code quality — 4 fixes (TODO comments, fire-and-forget notes, design notes, table name validation), 2 verified N/A, 1 upstream
- B3-4: Config PATCH→PUT alignment (admin-v2 config.ts matched to SaaS backend)
This commit is contained in:
iven
2026-04-03 21:34:56 +08:00
parent 305984c982
commit 2ceeeaba3d
17 changed files with 1157 additions and 81 deletions

View File

@@ -9,7 +9,7 @@ import { useAgentStore } from '../store/agentStore';
import { useConfigStore } from '../store/configStore';
import { type UnlistenFn } from '@tauri-apps/api/event';
import { safeListenEvent } from '../lib/safe-tauri';
import { Paperclip, SquarePen, ArrowUp, MessageSquare, Download, X, FileText, Image as ImageIcon } from 'lucide-react';
import { Paperclip, SquarePen, ArrowUp, MessageSquare, Download, X, FileText, Image as ImageIcon, Search } from 'lucide-react';
import { Button, EmptyState, MessageListSkeleton, LoadingDots } from './ui';
import { ResizableChatLayout } from './ai/ResizableChatLayout';
import { ArtifactPanel } from './ai/ArtifactPanel';
@@ -18,7 +18,7 @@ import { listItemVariants, defaultTransition, fadeInVariants } from '../lib/anim
import { FirstConversationPrompt } from './FirstConversationPrompt';
import { ClassroomPlayer } from './classroom_player';
import { useClassroomStore } from '../store/classroomStore';
// MessageSearch temporarily removed during DeerFlow redesign
import { MessageSearch } from './MessageSearch';
import { OfflineIndicator } from './OfflineIndicator';
import {
useVirtualizedMessages,
@@ -67,6 +67,7 @@ export function ChatArea() {
const [input, setInput] = useState('');
const [pendingFiles, setPendingFiles] = useState<File[]>([]);
const [searchOpen, setSearchOpen] = useState(false); const [searchOpen, setSearchOpen] = useState(false);
const scrollRef = useRef<HTMLDivElement>(null);
const textareaRef = useRef<HTMLTextAreaElement>(null);
const messageRefs = useRef<Map<string, HTMLDivElement>>(new Map());
@@ -325,6 +326,17 @@ export function ChatArea() {
);
})()}
<OfflineIndicator compact />
{messages.length > 0 && (
<Button
variant="ghost"
size="sm"
onClick={() => setSearchOpen((prev) => !prev)}
className={`flex items-center gap-1 rounded-lg transition-colors ${searchOpen ? 'text-orange-600 dark:text-orange-400 bg-orange-50 dark:bg-orange-900/20' : 'text-gray-600 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-gray-800'}`}
title="搜索消息"
>
<Search className="w-3.5 h-3.5" />
</Button>
)}
{messages.length > 0 && (
<Button
variant="ghost"
@@ -352,6 +364,27 @@ export function ChatArea() {
</div>
</div>
{/* MessageSearch panel */}
<AnimatePresence>
{searchOpen && messages.length > 0 && (
<motion.div
key="message-search"
initial={{ opacity: 0, height: 0 }}
animate={{ opacity: 1, height: 'auto' }}
exit={{ opacity: 0, height: 0 }}
transition={{ duration: 0.2 }}
className="border-b border-gray-100 dark:border-gray-800 bg-gray-50 dark:bg-gray-800/50 overflow-hidden"
>
<div className="px-6 py-3 max-w-4xl mx-auto">
<MessageSearch onNavigateToMessage={(id) => {
const el = messageRefs.current.get(id);
if (el) el.scrollIntoView({ behavior: 'smooth', block: 'center' });
}} />
</div>
</motion.div>
)}
</AnimatePresence>
{/* Messages */}
<Conversation className="flex-1 bg-white dark:bg-gray-900">
<AnimatePresence mode="popLayout">