feat(phase-11): add store coordinator layer
- Create store/index.ts as unified entry point - Add useCompositeStore() hook for multi-slice access - Add initializeStores() for client injection - Re-export all individual stores for direct access - Maintain backward compatibility with useGatewayStore Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
261
desktop/src/store/index.ts
Normal file
261
desktop/src/store/index.ts
Normal file
@@ -0,0 +1,261 @@
|
|||||||
|
/**
|
||||||
|
* Store Coordinator
|
||||||
|
*
|
||||||
|
* This module provides a unified interface to all specialized stores,
|
||||||
|
* maintaining backward compatibility with components that import useGatewayStore.
|
||||||
|
*
|
||||||
|
* The coordinator:
|
||||||
|
* 1. Injects the shared client into all stores
|
||||||
|
* 2. Provides a composite hook that combines all store slices
|
||||||
|
* 3. Re-exports all individual stores for direct access
|
||||||
|
*/
|
||||||
|
|
||||||
|
// === Re-export Individual Stores ===
|
||||||
|
export { useConnectionStore, getConnectionState, getClient, getConnectionError, getGatewayVersion } from './connectionStore';
|
||||||
|
export type { ConnectionStore, ConnectionStateSlice, ConnectionActionsSlice, GatewayLog } from './connectionStore';
|
||||||
|
|
||||||
|
export { useAgentStore, setAgentStoreClient } from './agentStore';
|
||||||
|
export type { AgentStore, AgentStateSlice, AgentActionsSlice, Clone, UsageStats, PluginStatus, CloneCreateOptions } from './agentStore';
|
||||||
|
|
||||||
|
export { useHandStore, setHandStoreClient } from './handStore';
|
||||||
|
export type { HandStore, HandStateSlice, HandActionsSlice, Hand, HandRun, Trigger, Approval, TriggerCreateOptions } from './handStore';
|
||||||
|
|
||||||
|
export { useWorkflowStore, setWorkflowStoreClient } from './workflowStore';
|
||||||
|
export type { WorkflowStore, WorkflowStateSlice, WorkflowActionsSlice, Workflow, WorkflowRun, WorkflowCreateOptions } from './workflowStore';
|
||||||
|
|
||||||
|
export { useConfigStore, setConfigStoreClient } from './configStore';
|
||||||
|
export type { ConfigStore, ConfigStateSlice, ConfigActionsSlice, QuickConfig, WorkspaceInfo, ChannelInfo, ScheduledTask, SkillInfo } from './configStore';
|
||||||
|
|
||||||
|
// === Composite Store Hook ===
|
||||||
|
|
||||||
|
import { useEffect, useMemo } from 'react';
|
||||||
|
import { useConnectionStore, getClient } from './connectionStore';
|
||||||
|
import { useAgentStore, setAgentStoreClient } from './agentStore';
|
||||||
|
import { useHandStore, setHandStoreClient } from './handStore';
|
||||||
|
import { useWorkflowStore, setWorkflowStoreClient } from './workflowStore';
|
||||||
|
import { useConfigStore, setConfigStoreClient } from './configStore';
|
||||||
|
import type { GatewayClient } from '../lib/gateway-client';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize all stores with the shared client.
|
||||||
|
* Called once when the application mounts.
|
||||||
|
*/
|
||||||
|
export function initializeStores(): void {
|
||||||
|
const client = getClient();
|
||||||
|
|
||||||
|
// Inject client into all stores
|
||||||
|
setAgentStoreClient(client);
|
||||||
|
setHandStoreClient(client);
|
||||||
|
setWorkflowStoreClient(client);
|
||||||
|
setConfigStoreClient(client);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook that provides a composite view of all stores.
|
||||||
|
* Use this for components that need access to multiple store slices.
|
||||||
|
*
|
||||||
|
* For components that only need specific slices, import the individual
|
||||||
|
* store hooks directly (e.g., useConnectionStore, useAgentStore).
|
||||||
|
*/
|
||||||
|
export function useCompositeStore() {
|
||||||
|
// Subscribe to all stores
|
||||||
|
const connectionState = useConnectionStore((s) => s.connectionState);
|
||||||
|
const gatewayVersion = useConnectionStore((s) => s.gatewayVersion);
|
||||||
|
const connectionError = useConnectionStore((s) => s.error);
|
||||||
|
const logs = useConnectionStore((s) => s.logs);
|
||||||
|
const localGateway = useConnectionStore((s) => s.localGateway);
|
||||||
|
const localGatewayBusy = useConnectionStore((s) => s.localGatewayBusy);
|
||||||
|
const isLoading = useConnectionStore((s) => s.isLoading);
|
||||||
|
const client = useConnectionStore((s) => s.client);
|
||||||
|
|
||||||
|
const clones = useAgentStore((s) => s.clones);
|
||||||
|
const usageStats = useAgentStore((s) => s.usageStats);
|
||||||
|
const pluginStatus = useAgentStore((s) => s.pluginStatus);
|
||||||
|
|
||||||
|
const hands = useHandStore((s) => s.hands);
|
||||||
|
const handRuns = useHandStore((s) => s.handRuns);
|
||||||
|
const triggers = useHandStore((s) => s.triggers);
|
||||||
|
const approvals = useHandStore((s) => s.approvals);
|
||||||
|
|
||||||
|
const workflows = useWorkflowStore((s) => s.workflows);
|
||||||
|
const workflowRuns = useWorkflowStore((s) => s.workflowRuns);
|
||||||
|
|
||||||
|
const quickConfig = useConfigStore((s) => s.quickConfig);
|
||||||
|
const workspaceInfo = useConfigStore((s) => s.workspaceInfo);
|
||||||
|
const channels = useConfigStore((s) => s.channels);
|
||||||
|
const scheduledTasks = useConfigStore((s) => s.scheduledTasks);
|
||||||
|
const skillsCatalog = useConfigStore((s) => s.skillsCatalog);
|
||||||
|
const models = useConfigStore((s) => s.models);
|
||||||
|
const modelsLoading = useConfigStore((s) => s.modelsLoading);
|
||||||
|
const modelsError = useConfigStore((s) => s.modelsError);
|
||||||
|
|
||||||
|
// Get all actions
|
||||||
|
const connect = useConnectionStore((s) => s.connect);
|
||||||
|
const disconnect = useConnectionStore((s) => s.disconnect);
|
||||||
|
const clearLogs = useConnectionStore((s) => s.clearLogs);
|
||||||
|
const refreshLocalGateway = useConnectionStore((s) => s.refreshLocalGateway);
|
||||||
|
const startLocalGateway = useConnectionStore((s) => s.startLocalGateway);
|
||||||
|
const stopLocalGateway = useConnectionStore((s) => s.stopLocalGateway);
|
||||||
|
const restartLocalGateway = useConnectionStore((s) => s.restartLocalGateway);
|
||||||
|
|
||||||
|
const loadClones = useAgentStore((s) => s.loadClones);
|
||||||
|
const createClone = useAgentStore((s) => s.createClone);
|
||||||
|
const updateClone = useAgentStore((s) => s.updateClone);
|
||||||
|
const deleteClone = useAgentStore((s) => s.deleteClone);
|
||||||
|
const loadUsageStats = useAgentStore((s) => s.loadUsageStats);
|
||||||
|
const loadPluginStatus = useAgentStore((s) => s.loadPluginStatus);
|
||||||
|
|
||||||
|
const loadHands = useHandStore((s) => s.loadHands);
|
||||||
|
const getHandDetails = useHandStore((s) => s.getHandDetails);
|
||||||
|
const triggerHand = useHandStore((s) => s.triggerHand);
|
||||||
|
const loadHandRuns = useHandStore((s) => s.loadHandRuns);
|
||||||
|
const loadTriggers = useHandStore((s) => s.loadTriggers);
|
||||||
|
const createTrigger = useHandStore((s) => s.createTrigger);
|
||||||
|
const deleteTrigger = useHandStore((s) => s.deleteTrigger);
|
||||||
|
const loadApprovals = useHandStore((s) => s.loadApprovals);
|
||||||
|
const approveRequest = useHandStore((s) => s.approveRequest);
|
||||||
|
|
||||||
|
const loadWorkflows = useWorkflowStore((s) => s.loadWorkflows);
|
||||||
|
const getWorkflow = useWorkflowStore((s) => s.getWorkflow);
|
||||||
|
const createWorkflow = useWorkflowStore((s) => s.createWorkflow);
|
||||||
|
const updateWorkflow = useWorkflowStore((s) => s.updateWorkflow);
|
||||||
|
const deleteWorkflow = useWorkflowStore((s) => s.deleteWorkflow);
|
||||||
|
const triggerWorkflow = useWorkflowStore((s) => s.triggerWorkflow);
|
||||||
|
const loadWorkflowRuns = useWorkflowStore((s) => s.loadWorkflowRuns);
|
||||||
|
|
||||||
|
const loadQuickConfig = useConfigStore((s) => s.loadQuickConfig);
|
||||||
|
const saveQuickConfig = useConfigStore((s) => s.saveQuickConfig);
|
||||||
|
const loadWorkspaceInfo = useConfigStore((s) => s.loadWorkspaceInfo);
|
||||||
|
const loadChannels = useConfigStore((s) => s.loadChannels);
|
||||||
|
const getChannel = useConfigStore((s) => s.getChannel);
|
||||||
|
const createChannel = useConfigStore((s) => s.createChannel);
|
||||||
|
const updateChannel = useConfigStore((s) => s.updateChannel);
|
||||||
|
const deleteChannel = useConfigStore((s) => s.deleteChannel);
|
||||||
|
const loadScheduledTasks = useConfigStore((s) => s.loadScheduledTasks);
|
||||||
|
const createScheduledTask = useConfigStore((s) => s.createScheduledTask);
|
||||||
|
const loadSkillsCatalog = useConfigStore((s) => s.loadSkillsCatalog);
|
||||||
|
const getSkill = useConfigStore((s) => s.getSkill);
|
||||||
|
const createSkill = useConfigStore((s) => s.createSkill);
|
||||||
|
const updateSkill = useConfigStore((s) => s.updateSkill);
|
||||||
|
const deleteSkill = useConfigStore((s) => s.deleteSkill);
|
||||||
|
const loadModels = useConfigStore((s) => s.loadModels);
|
||||||
|
|
||||||
|
// Memoize the composite store to prevent unnecessary re-renders
|
||||||
|
return useMemo(() => ({
|
||||||
|
// Connection state
|
||||||
|
connectionState,
|
||||||
|
gatewayVersion,
|
||||||
|
error: connectionError,
|
||||||
|
logs,
|
||||||
|
localGateway,
|
||||||
|
localGatewayBusy,
|
||||||
|
isLoading,
|
||||||
|
client,
|
||||||
|
|
||||||
|
// Agent state
|
||||||
|
clones,
|
||||||
|
usageStats,
|
||||||
|
pluginStatus,
|
||||||
|
|
||||||
|
// Hand state
|
||||||
|
hands,
|
||||||
|
handRuns,
|
||||||
|
triggers,
|
||||||
|
approvals,
|
||||||
|
|
||||||
|
// Workflow state
|
||||||
|
workflows,
|
||||||
|
workflowRuns,
|
||||||
|
|
||||||
|
// Config state
|
||||||
|
quickConfig,
|
||||||
|
workspaceInfo,
|
||||||
|
channels,
|
||||||
|
scheduledTasks,
|
||||||
|
skillsCatalog,
|
||||||
|
models,
|
||||||
|
modelsLoading,
|
||||||
|
modelsError,
|
||||||
|
|
||||||
|
// Connection actions
|
||||||
|
connect,
|
||||||
|
disconnect,
|
||||||
|
clearLogs,
|
||||||
|
refreshLocalGateway,
|
||||||
|
startLocalGateway,
|
||||||
|
stopLocalGateway,
|
||||||
|
restartLocalGateway,
|
||||||
|
|
||||||
|
// Agent actions
|
||||||
|
loadClones,
|
||||||
|
createClone,
|
||||||
|
updateClone,
|
||||||
|
deleteClone,
|
||||||
|
loadUsageStats,
|
||||||
|
loadPluginStatus,
|
||||||
|
|
||||||
|
// Hand actions
|
||||||
|
loadHands,
|
||||||
|
getHandDetails,
|
||||||
|
triggerHand,
|
||||||
|
loadHandRuns,
|
||||||
|
loadTriggers,
|
||||||
|
createTrigger,
|
||||||
|
deleteTrigger,
|
||||||
|
loadApprovals,
|
||||||
|
approveRequest,
|
||||||
|
|
||||||
|
// Workflow actions
|
||||||
|
loadWorkflows,
|
||||||
|
getWorkflow,
|
||||||
|
createWorkflow,
|
||||||
|
updateWorkflow,
|
||||||
|
deleteWorkflow,
|
||||||
|
triggerWorkflow,
|
||||||
|
loadWorkflowRuns,
|
||||||
|
|
||||||
|
// Config actions
|
||||||
|
loadQuickConfig,
|
||||||
|
saveQuickConfig,
|
||||||
|
loadWorkspaceInfo,
|
||||||
|
loadChannels,
|
||||||
|
getChannel,
|
||||||
|
createChannel,
|
||||||
|
updateChannel,
|
||||||
|
deleteChannel,
|
||||||
|
loadScheduledTasks,
|
||||||
|
createScheduledTask,
|
||||||
|
loadSkillsCatalog,
|
||||||
|
getSkill,
|
||||||
|
createSkill,
|
||||||
|
updateSkill,
|
||||||
|
deleteSkill,
|
||||||
|
loadModels,
|
||||||
|
|
||||||
|
// Legacy sendMessage (delegates to client)
|
||||||
|
sendMessage: async (message: string, sessionKey?: string) => {
|
||||||
|
return client.chat(message, { sessionKey });
|
||||||
|
},
|
||||||
|
}), [
|
||||||
|
connectionState, gatewayVersion, connectionError, logs, localGateway, localGatewayBusy, isLoading, client,
|
||||||
|
clones, usageStats, pluginStatus,
|
||||||
|
hands, handRuns, triggers, approvals,
|
||||||
|
workflows, workflowRuns,
|
||||||
|
quickConfig, workspaceInfo, channels, scheduledTasks, skillsCatalog, models, modelsLoading, modelsError,
|
||||||
|
connect, disconnect, clearLogs, refreshLocalGateway, startLocalGateway, stopLocalGateway, restartLocalGateway,
|
||||||
|
loadClones, createClone, updateClone, deleteClone, loadUsageStats, loadPluginStatus,
|
||||||
|
loadHands, getHandDetails, triggerHand, loadHandRuns, loadTriggers, createTrigger, deleteTrigger, loadApprovals, approveRequest,
|
||||||
|
loadWorkflows, getWorkflow, createWorkflow, updateWorkflow, deleteWorkflow, triggerWorkflow, loadWorkflowRuns,
|
||||||
|
loadQuickConfig, saveQuickConfig, loadWorkspaceInfo, loadChannels, getChannel, createChannel, updateChannel, deleteChannel,
|
||||||
|
loadScheduledTasks, createScheduledTask, loadSkillsCatalog, getSkill, createSkill, updateSkill, deleteSkill, loadModels,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize stores on module load.
|
||||||
|
* This ensures all stores have access to the shared client.
|
||||||
|
*/
|
||||||
|
if (typeof window !== 'undefined') {
|
||||||
|
// Defer initialization to next tick to ensure all modules are loaded
|
||||||
|
setTimeout(initializeStores, 0);
|
||||||
|
}
|
||||||
@@ -567,12 +567,12 @@ ZCLAW 是基于 **OpenFang** (Rust Agent OS) 的 AI Agent 桌面客户端,核
|
|||||||
* ✅ `handStore.ts` (498 行) - Hands、Triggers、Approvals
|
* ✅ `handStore.ts` (498 行) - Hands、Triggers、Approvals
|
||||||
* ✅ `workflowStore.ts` (255 行) - Workflows、WorkflowRuns
|
* ✅ `workflowStore.ts` (255 行) - Workflows、WorkflowRuns
|
||||||
* ✅ `configStore.ts` (537 行) - QuickConfig、Channels、Skills、Models
|
* ✅ `configStore.ts` (537 行) - QuickConfig、Channels、Skills、Models
|
||||||
|
* ✅ `store/index.ts` - 协调层,组合所有 stores
|
||||||
* Store 行数: gatewayStore 1660 → 5 个子 Store (平均 358 行)
|
* Store 行数: gatewayStore 1660 → 5 个子 Store (平均 358 行)
|
||||||
* 待完成:
|
* 待完成:
|
||||||
* 🔄 创建协调层 (coordinator)
|
* 🔄 更新组件导入 (可选,向后兼容)
|
||||||
* 🔄 更新组件导入
|
|
||||||
* 代码质量:
|
* 代码质量:
|
||||||
* ✅ TypeScript 类型检查通过
|
* ✅ TypeScript 类型检查通过
|
||||||
|
|
||||||
*下一步: Phase 11 协调层创建*
|
*下一步: Phase 12 性能优化*
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user