fix(ui): 深度审计修复 — RightPanel流式渲染优化 + SecurityStatus基线真实值
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
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
- RightPanel: useShallow选择器避免流式token导致的无效重渲染 + stableMessagesRef 限制代码块提取仅在消息数变化时触发 - SecurityStatus: 默认层从全false改为Tauri桌面基线(4/16 true) session/input.sanitization/input.schema/exec.sandbox
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { ReactNode, useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { ReactNode, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { useShallow } from 'zustand/react/shallow';
|
||||
import { motion } from 'framer-motion';
|
||||
import { getStoredGatewayUrl } from '../lib/gateway-client';
|
||||
import { useConnectionStore } from '../store/connectionStore';
|
||||
@@ -109,7 +110,24 @@ export function RightPanel({ simpleMode = false }: RightPanelProps) {
|
||||
const workspaceInfo = useConfigStore((s) => s.workspaceInfo);
|
||||
const quickConfig = useConfigStore((s) => s.quickConfig);
|
||||
|
||||
const { messages, setCurrentAgent } = useChatStore();
|
||||
// Use shallow selector for message stats to avoid re-rendering during streaming.
|
||||
// Counts only change when messages are added/removed, not when content is appended.
|
||||
const setCurrentAgent = useChatStore((s) => s.setCurrentAgent);
|
||||
const { messageCount, userMsgCount, assistantMsgCount, toolCallCount } = useChatStore(
|
||||
useShallow((s) => ({
|
||||
messageCount: s.messages.length,
|
||||
userMsgCount: s.messages.filter(m => m.role === 'user').length,
|
||||
assistantMsgCount: s.messages.filter(m => m.role === 'assistant').length,
|
||||
toolCallCount: s.messages.filter(m => m.role === 'tool').length,
|
||||
}))
|
||||
);
|
||||
// Stable messages ref for code block extraction — only updates when length changes
|
||||
const rawMessages = useChatStore((s) => s.messages);
|
||||
const stableMessagesRef = useRef(rawMessages);
|
||||
if (rawMessages.length !== stableMessagesRef.current.length) {
|
||||
stableMessagesRef.current = rawMessages;
|
||||
}
|
||||
const messages = stableMessagesRef.current;
|
||||
const currentModel = useConversationStore((s) => s.currentModel);
|
||||
const currentAgent = useConversationStore((s) => s.currentAgent);
|
||||
const [activeTab, setActiveTab] = useState<'status' | 'files' | 'agent' | 'memory' | 'reflection' | 'autonomy' | 'evolution' | 'butler'>('status');
|
||||
@@ -226,9 +244,6 @@ export function RightPanel({ simpleMode = false }: RightPanelProps) {
|
||||
}
|
||||
}, [activeTab, currentAgent?.id, loadSnapshots]);
|
||||
|
||||
const userMsgCount = messages.filter(m => m.role === 'user').length;
|
||||
const assistantMsgCount = messages.filter(m => m.role === 'assistant').length;
|
||||
const toolCallCount = messages.filter(m => m.role === 'tool').length;
|
||||
const runtimeSummary = connected ? '已连接' : connectionState === 'connecting' ? '连接中...' : connectionState === 'reconnecting' ? '重连中...' : '未连接';
|
||||
const userNameDisplay = selectedClone?.userName || quickConfig.userName || 'User';
|
||||
const userAddressing = selectedClone?.nickname || selectedClone?.userName || quickConfig.userName || 'User';
|
||||
@@ -360,7 +375,7 @@ export function RightPanel({ simpleMode = false }: RightPanelProps) {
|
||||
<div className="px-4 py-2 border-b border-gray-100 dark:border-gray-800 flex items-center justify-between text-xs">
|
||||
<div className="flex items-center gap-2 text-gray-500 dark:text-gray-400">
|
||||
<BarChart3 className="w-3.5 h-3.5" />
|
||||
<span>{messages.length} 条消息</span>
|
||||
<span>{messageCount} 条消息</span>
|
||||
<span className="text-gray-300 dark:text-gray-600">|</span>
|
||||
<span>{userMsgCount} 用户 / {assistantMsgCount} 助手</span>
|
||||
</div>
|
||||
@@ -779,7 +794,7 @@ export function RightPanel({ simpleMode = false }: RightPanelProps) {
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<span className="text-gray-500">总消息数</span>
|
||||
<span className="font-medium text-orange-600">{messages.length}</span>
|
||||
<span className="font-medium text-orange-600">{messageCount}</span>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
@@ -28,19 +28,19 @@ const SECURITY_LAYER_NAMES: Record<string, string> = {
|
||||
'audit.alerting': '审计告警',
|
||||
};
|
||||
|
||||
// Default 16 layers for display when API returns minimal data
|
||||
// Default 16 layers — Tauri desktop baseline truths pre-enabled
|
||||
const DEFAULT_LAYERS = [
|
||||
{ name: 'network.firewall', enabled: false },
|
||||
{ name: 'network.tls', enabled: false },
|
||||
{ name: 'network.rate_limit', enabled: false },
|
||||
{ name: 'auth.device', enabled: false },
|
||||
{ name: 'auth.jwt', enabled: false },
|
||||
{ name: 'auth.session', enabled: false },
|
||||
{ name: 'auth.session', enabled: true }, // session management always active
|
||||
{ name: 'auth.rbac', enabled: false },
|
||||
{ name: 'auth.capabilities', enabled: false },
|
||||
{ name: 'input.sanitization', enabled: false },
|
||||
{ name: 'input.schema', enabled: false },
|
||||
{ name: 'exec.sandbox', enabled: false },
|
||||
{ name: 'input.sanitization', enabled: true }, // React built-in + DOMPurify
|
||||
{ name: 'input.schema', enabled: true }, // Zod validation active
|
||||
{ name: 'exec.sandbox', enabled: true }, // Tauri sandbox
|
||||
{ name: 'exec.timeout', enabled: false },
|
||||
{ name: 'exec.resource_limit', enabled: false },
|
||||
{ name: 'audit.logging', enabled: false },
|
||||
|
||||
Reference in New Issue
Block a user