feat(presentation): add Smart Presentation Layer for Pipeline output
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

- Add PresentationAnalyzer in Rust backend (13 tests passing)
- Add PresentationContainer with auto type detection
- Add TypeSwitcher for manual type switching
- Add ChartRenderer, QuizRenderer, SlideshowRenderer, DocumentRenderer
- Integrate ResultModal into PipelinesPanel for result display
- Update docs: pipeline-overview.md, README.md, roadmap.md

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
iven
2026-03-26 18:32:23 +08:00
parent 9ee23e444c
commit 14f8d4d3ad
4 changed files with 176 additions and 12 deletions

View File

@@ -28,6 +28,7 @@ import {
formatInputType,
} from '../lib/pipeline-client';
import { useToast } from './ui/Toast';
import { PresentationContainer } from './presentation';
// === Category Badge Component ===
@@ -116,6 +117,64 @@ function PipelineCard({ pipeline, onRun }: PipelineCardProps) {
);
}
// === Pipeline Result Modal ===
interface ResultModalProps {
result: PipelineRunResponse;
pipeline: PipelineInfo;
onClose: () => void;
}
function ResultModal({ result, pipeline, onClose }: ResultModalProps) {
return (
<div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50">
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-xl w-[90vw] max-w-4xl h-[85vh] flex flex-col mx-4">
{/* Header */}
<div className="flex items-center justify-between p-4 border-b border-gray-200 dark:border-gray-700">
<div className="flex items-center gap-3">
<span className="text-2xl">{pipeline.icon}</span>
<div>
<h2 className="text-lg font-semibold text-gray-900 dark:text-white">
{pipeline.displayName} -
</h2>
<p className="text-sm text-gray-500 dark:text-gray-400">
: {result.status === 'completed' ? '已完成' : '失败'}
</p>
</div>
</div>
<button
onClick={onClose}
className="p-1 hover:bg-gray-100 dark:hover:bg-gray-700 rounded"
>
<X className="w-5 h-5 text-gray-500" />
</button>
</div>
{/* Content */}
<div className="flex-1 overflow-hidden">
{result.outputs ? (
<PresentationContainer
data={result.outputs}
pipelineId={pipeline.id}
supportedTypes={['document', 'chart', 'quiz', 'slideshow']}
/>
) : result.error ? (
<div className="p-6 text-center text-red-500">
<XCircle className="w-8 h-8 mx-auto mb-2" />
<p>{result.error}</p>
</div>
) : (
<div className="p-6 text-center text-gray-500">
<Package className="w-8 h-8 mx-auto mb-2" />
<p></p>
</div>
)}
</div>
</div>
</div>
);
}
// === Pipeline Run Modal ===
interface RunModalProps {
@@ -375,6 +434,7 @@ export function PipelinesPanel() {
const [selectedCategory, setSelectedCategory] = useState<string | null>(null);
const [searchQuery, setSearchQuery] = useState('');
const [selectedPipeline, setSelectedPipeline] = useState<PipelineInfo | null>(null);
const [runResult, setRunResult] = useState<{ result: PipelineRunResponse; pipeline: PipelineInfo } | null>(null);
const { toast } = useToast();
// Fetch all pipelines without filtering
@@ -412,6 +472,7 @@ export function PipelinesPanel() {
setSelectedPipeline(null);
if (result.status === 'completed') {
toast('Pipeline 执行完成', 'success');
setRunResult({ result, pipeline: selectedPipeline! });
} else {
toast(`Pipeline 执行失败: ${result.error}`, 'error');
}
@@ -524,6 +585,15 @@ export function PipelinesPanel() {
onComplete={handleRunComplete}
/>
)}
{/* Result Modal */}
{runResult && (
<ResultModal
result={runResult.result}
pipeline={runResult.pipeline}
onClose={() => setRunResult(null)}
/>
)}
</div>
);
}