chore: 提交所有工作进度 — SaaS 后端增强、Admin UI、桌面端集成
包含大量 SaaS 平台改进、Admin 管理后台更新、桌面端集成完善、 文档同步、测试文件重构等内容。为 QA 测试准备干净工作树。
This commit is contained in:
@@ -12,6 +12,7 @@ import { HandApprovalModal } from './components/HandApprovalModal';
|
||||
import { TopBar } from './components/TopBar';
|
||||
import { DetailDrawer } from './components/DetailDrawer';
|
||||
import { useConnectionStore } from './store/connectionStore';
|
||||
import { useSaaSStore } from './store/saasStore';
|
||||
import { useHandStore, type HandRun } from './store/handStore';
|
||||
import { useChatStore } from './store/chatStore';
|
||||
import { initializeStores } from './store';
|
||||
@@ -19,9 +20,10 @@ import { getStoredGatewayToken } from './lib/gateway-client';
|
||||
import { pageVariants, defaultTransition, fadeInVariants } from './lib/animations';
|
||||
import { Loader2 } from 'lucide-react';
|
||||
import { isTauriRuntime, getLocalGatewayStatus, startLocalGateway } from './lib/tauri-gateway';
|
||||
import { LoginPage } from './components/LoginPage';
|
||||
import { useOnboarding } from './lib/use-onboarding';
|
||||
import { intelligenceClient } from './lib/intelligence-client';
|
||||
import { loadEmbeddingConfig } from './lib/embedding-client';
|
||||
import { loadEmbeddingConfig, loadEmbeddingApiKey } from './lib/embedding-client';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { useProposalNotifications, ProposalNotificationHandler } from './lib/useProposalNotifications';
|
||||
import { useToast } from './components/ui/Toast';
|
||||
@@ -54,10 +56,11 @@ function App() {
|
||||
const [showApprovalModal, setShowApprovalModal] = useState(false);
|
||||
|
||||
const connect = useConnectionStore((s) => s.connect);
|
||||
const isLoggedIn = useSaaSStore((s) => s.isLoggedIn);
|
||||
const hands = useHandStore((s) => s.hands);
|
||||
const approveHand = useHandStore((s) => s.approveHand);
|
||||
const loadHands = useHandStore((s) => s.loadHands);
|
||||
const { setCurrentAgent, newConversation } = useChatStore();
|
||||
const { setCurrentAgent } = useChatStore();
|
||||
const { isNeeded: onboardingNeeded, isLoading: onboardingLoading, markCompleted } = useOnboarding();
|
||||
|
||||
// Proposal notifications
|
||||
@@ -132,6 +135,9 @@ function App() {
|
||||
let mounted = true;
|
||||
|
||||
const bootstrap = async () => {
|
||||
// 未登录时不启动 bootstrap
|
||||
if (!useSaaSStore.getState().isLoggedIn) return;
|
||||
|
||||
try {
|
||||
// Step 1: Check and start local gateway in Tauri environment
|
||||
if (isTauriRuntime()) {
|
||||
@@ -234,12 +240,33 @@ function App() {
|
||||
|
||||
// Step 5: Restore embedding config to Rust backend
|
||||
try {
|
||||
// Migrate plaintext embedding apiKey to secure storage if present
|
||||
try {
|
||||
const embStored = localStorage.getItem('zclaw-embedding-config');
|
||||
if (embStored) {
|
||||
const embParsed = JSON.parse(embStored);
|
||||
if (embParsed.apiKey && embParsed.apiKey.trim()) {
|
||||
const { saveEmbeddingApiKey } = await import('./lib/embedding-client');
|
||||
const { secureStorage } = await import('./lib/secure-storage');
|
||||
// Only migrate if not already in secure storage
|
||||
const existing = await secureStorage.get('zclaw-secure-embedding-apikey');
|
||||
if (!existing) {
|
||||
await saveEmbeddingApiKey(embParsed.apiKey);
|
||||
}
|
||||
// Strip apiKey from localStorage
|
||||
const { apiKey: _, ...stripped } = embParsed;
|
||||
localStorage.setItem('zclaw-embedding-config', JSON.stringify(stripped));
|
||||
}
|
||||
}
|
||||
} catch { /* migration failure is non-critical */ }
|
||||
|
||||
const embConfig = loadEmbeddingConfig();
|
||||
if (embConfig.enabled && embConfig.provider !== 'local' && embConfig.apiKey) {
|
||||
const embApiKey = await loadEmbeddingApiKey();
|
||||
if (embConfig.enabled && embConfig.provider !== 'local' && embApiKey) {
|
||||
setBootstrapStatus('Restoring embedding configuration...');
|
||||
await invoke('viking_configure_embedding', {
|
||||
provider: embConfig.provider,
|
||||
apiKey: embConfig.apiKey,
|
||||
apiKey: embApiKey,
|
||||
model: embConfig.model || undefined,
|
||||
endpoint: embConfig.endpoint || undefined,
|
||||
});
|
||||
@@ -252,8 +279,10 @@ function App() {
|
||||
|
||||
// Step 5b: Configure summary driver using active LLM (for L0/L1 generation)
|
||||
try {
|
||||
const { getDefaultModelConfig } = await import('./store/connectionStore');
|
||||
const modelConfig = getDefaultModelConfig();
|
||||
const { getDefaultModelConfigAsync, migrateModelApiKeysToSecureStorage } = await import('./store/connectionStore');
|
||||
// Migrate any plaintext API keys to secure storage (idempotent)
|
||||
await migrateModelApiKeysToSecureStorage();
|
||||
const modelConfig = await getDefaultModelConfigAsync();
|
||||
if (modelConfig && modelConfig.apiKey && modelConfig.baseUrl) {
|
||||
setBootstrapStatus('Configuring summary driver...');
|
||||
await invoke('viking_configure_summary_driver', {
|
||||
@@ -288,7 +317,7 @@ function App() {
|
||||
clearInterval(window.__ZCLAW_STATS_SYNC_INTERVAL__);
|
||||
}
|
||||
};
|
||||
}, [connect, onboardingNeeded, onboardingLoading]);
|
||||
}, [connect, onboardingNeeded, onboardingLoading, isLoggedIn]);
|
||||
|
||||
// Handle onboarding completion
|
||||
const handleOnboardingSuccess = (clone: Clone) => {
|
||||
@@ -312,11 +341,10 @@ function App() {
|
||||
setMainContentView(view);
|
||||
};
|
||||
|
||||
// 处理新对话
|
||||
const handleNewChat = () => {
|
||||
newConversation();
|
||||
setMainContentView('chat');
|
||||
};
|
||||
// 登录门禁 — 必须登录才能使用
|
||||
if (!isLoggedIn) {
|
||||
return <LoginPage />;
|
||||
}
|
||||
|
||||
if (view === 'settings') {
|
||||
return <SettingsLayout onBack={() => setView('main')} />;
|
||||
@@ -384,7 +412,6 @@ function App() {
|
||||
<Sidebar
|
||||
onOpenSettings={() => setView('settings')}
|
||||
onMainViewChange={handleMainViewChange}
|
||||
onNewChat={handleNewChat}
|
||||
/>
|
||||
|
||||
{/* 主内容区 */}
|
||||
|
||||
Reference in New Issue
Block a user