()
| 107 | } |
| 108 | |
| 109 | function AppShell() { |
| 110 | const { language, preference: languagePreference, setPreference: setLanguagePreference, t } = useI18n(); |
| 111 | const [projects, setProjects] = useState<SourceRecord[]>([]); |
| 112 | const [documents, setDocuments] = useState<DocumentRecord[]>([]); |
| 113 | const [projectStats, setProjectStats] = useState<ProjectStatsRecord | null>(null); |
| 114 | const [projectGraph, setProjectGraph] = useState<ProjectGraphRecord | null>(null); |
| 115 | const [selectedProjectId, setSelectedProjectId] = useState(""); |
| 116 | const [selectedDocumentId, setSelectedDocumentId] = useState(""); |
| 117 | const [selectedDocument, setSelectedDocument] = useState<DocumentRecord | null>(null); |
| 118 | const [chunks, setChunks] = useState<ChunkRecord[]>([]); |
| 119 | const [events, setEvents] = useState<EventRecord[]>([]); |
| 120 | const [entities, setEntities] = useState<EntityRecord[]>([]); |
| 121 | const [sessionsByProjectId, setSessionsByProjectId] = useState<Record<string, McpSessionRecord[]>>({}); |
| 122 | const [expandedProjectIds, setExpandedProjectIds] = useState<Set<string>>(() => new Set()); |
| 123 | const [mcpDetail, setMcpDetail] = useState<McpSessionDetail | null>(null); |
| 124 | const [aiSettings, setAiSettings] = useState<PublicAiProviderSettings | null>(null); |
| 125 | const [mcpSettings, setMcpSettings] = useState<PublicMcpSettings | null>(null); |
| 126 | const [workspaceView, setWorkspaceView] = useState<WorkspaceView>("chat"); |
| 127 | const [resultView, setResultView] = useState<ResultView>("overview"); |
| 128 | const [contextPanelMode, setContextPanelMode] = useState<ContextPanelMode>("process"); |
| 129 | const [drawer, setDrawer] = useState<DetailDrawer>(null); |
| 130 | const [showArchivedProjects, setShowArchivedProjects] = useState(false); |
| 131 | const [showArchivedDocuments, setShowArchivedDocuments] = useState(false); |
| 132 | const [newProjectName, setNewProjectName] = useState(""); |
| 133 | const [status, setStatus] = useState(() => t("正在加载 SAG...", "Loading SAG...")); |
| 134 | const [error, setError] = useState(""); |
| 135 | const [uploadJobs, setUploadJobs] = useState<UploadJobRecord[]>([]); |
| 136 | const [isUploadQueueExpanded, setIsUploadQueueExpanded] = useState(false); |
| 137 | const [isSavingSettings, setIsSavingSettings] = useState(false); |
| 138 | const [searchQuery, setSearchQuery] = useState(() => t(DEFAULT_SEARCH_QUERY_ZH, DEFAULT_SEARCH_QUERY_EN)); |
| 139 | const [searchMode, setSearchMode] = useState<SearchMode>("fast"); |
| 140 | const [searchResult, setSearchResult] = useState<SearchResult | null>(null); |
| 141 | const [processSteps, setProcessSteps] = useState<ProcessStep[]>([]); |
| 142 | const [modelLogs, setModelLogs] = useState<ModelCallLogRecord[]>(() => loadStoredModelLogs()); |
| 143 | const [modelLogCursor, setModelLogCursor] = useState(() => loadStoredModelLogCursor()); |
| 144 | const [isSearching, setIsSearching] = useState(false); |
| 145 | const [mcpInput, setMcpInput] = useState(""); |
| 146 | const [isMcpRunning, setIsMcpRunning] = useState(false); |
| 147 | const [pendingUserMessage, setPendingUserMessage] = useState(""); |
| 148 | const [streamingAssistantText, setStreamingAssistantText] = useState(""); |
| 149 | const [runningMcpSearches, setRunningMcpSearches] = useState<RunningMcpSearch[]>([]); |
| 150 | const fileInputRef = useRef<HTMLInputElement | null>(null); |
| 151 | const searchStartedAtRef = useRef<number | null>(null); |
| 152 | const refreshedUploadJobsRef = useRef<Set<string>>(new Set()); |
| 153 | const modelLogCursorRef = useRef(modelLogCursor); |
| 154 | const pendingSessionIdRef = useRef<string | null>(null); |
| 155 | const mcpAbortControllerRef = useRef<AbortController | null>(null); |
| 156 | |
| 157 | const selectedProject = useMemo( |
| 158 | () => projects.find((project) => project.id === selectedProjectId) ?? null, |
| 159 | [projects, selectedProjectId] |
| 160 | ); |
| 161 | |
| 162 | const visibleDocuments = useMemo( |
| 163 | () => documents.filter((document) => showArchivedDocuments || !document.archivedAt), |
| 164 | [documents, showArchivedDocuments] |
| 165 | ); |
| 166 |
nothing calls this directly
no test coverage detected