feat(frontend): wire Phase 1.2 components into App layout

Replaces placeholder areas with QueryInput, KeywordsDisplay, ResponsePanel, IngestPanel, and ErrorBoundary. App.tsx now holds TanStack Query mutation state and passes props to all components.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
Woody 2026-04-23 11:24:46 +08:00
parent a7d5dc610a
commit 6b544808de
1 changed files with 35 additions and 13 deletions

View File

@ -1,7 +1,12 @@
import React from 'react'
import { QueryClientProvider } from '@tanstack/react-query'
import { queryClient } from './lib/queries'
import { queryClient, useQueryDocument, useIngestDocument } from './lib/queries'
import { Film } from 'lucide-react'
import { QueryInput } from './components/QueryInput'
import { KeywordsDisplay } from './components/KeywordsDisplay'
import { ResponsePanel } from './components/ResponsePanel'
import { IngestPanel } from './components/IngestPanel'
import { ErrorBoundary } from './components/ErrorBoundary'
const VideoPlaceholder: React.FC = () => {
return (
@ -14,25 +19,40 @@ const VideoPlaceholder: React.FC = () => {
)
}
const RightTop: React.FC = () => {
return <div className="h-full border rounded border-dashed border-gray-300" />
const AppContent: React.FC = () => {
const queryMutation = useQueryDocument()
const ingestMutation = useIngestDocument()
const handleQuerySubmit = (question: string): void => {
queryMutation.mutate({ question })
}
const BottomArea: React.FC = () => {
return <div className="border border-dashed border-gray-300 rounded h-full" />
const handleFileUpload = (file: File): void => {
ingestMutation.mutate(file)
}
const AppLayout: React.FC = () => {
return (
<div className="h-screen grid grid-rows-[1fr_auto] grid-cols-2">
<div className="border-r border-b border-gray-200 p-4">
<VideoPlaceholder />
</div>
<div className="border-b border-gray-200 p-4">
<RightTop />
<div className="border-b border-gray-200 p-4 flex flex-col gap-4 overflow-y-auto">
<QueryInput onSubmit={handleQuerySubmit} isLoading={queryMutation.isPending} />
<KeywordsDisplay keywords={queryMutation.data?.keywords} isLoading={queryMutation.isPending} />
<IngestPanel
onUpload={handleFileUpload}
isLoading={ingestMutation.isPending}
success={ingestMutation.isSuccess ? ingestMutation.data?.filename ?? null : null}
error={ingestMutation.isError ? (ingestMutation.error instanceof Error ? ingestMutation.error.message : 'Upload failed') : null}
/>
</div>
<div className="col-span-2 p-4 border-t border-gray-200">
<BottomArea />
<div className="col-span-2 p-4 border-t border-gray-200 overflow-y-auto">
<ResponsePanel
answer={queryMutation.data?.answer ?? null}
sources={queryMutation.data?.sources ?? []}
isLoading={queryMutation.isPending}
error={queryMutation.isError ? (queryMutation.error instanceof Error ? queryMutation.error.message : 'Query failed') : null}
/>
</div>
</div>
)
@ -41,7 +61,9 @@ const AppLayout: React.FC = () => {
export default function App(): JSX.Element {
return (
<QueryClientProvider client={queryClient}>
<AppLayout />
<ErrorBoundary>
<AppContent />
</ErrorBoundary>
</QueryClientProvider>
)
}