'use client'; import { useMemo } from 'react'; import { Download } from '@phosphor-icons/react'; import type { PairwiseAlignResult } from '@/types/pipeline'; import PhyloTreeViewer from '@/components/phylo/PhyloTreeViewer'; import { ConservationTrack } from '@/components/alignment/ConservationTrack'; import { PairwiseResultDisplay } from '@/components/alignment/PairwiseResultDisplay'; import { AlignmentStatsBar } from '@/components/alignment/AlignmentStatsBar'; import { AlignmentBlock } from '@/components/alignment/AlignmentBlock'; import { computeAlignmentStats, parseAlignedFasta } from '@/lib/alignment-stats'; interface MSAResultPanelProps { alnFasta: string; phylotree?: string | null; sequenceCount?: number; alignmentMode?: 'global' | 'local'; pairwise?: PairwiseAlignResult | null; pairwiseSubject?: string | null; jobId?: string; } export function MSAResultPanel({ alnFasta, phylotree, sequenceCount, alignmentMode, pairwise, pairwiseSubject, jobId, }: MSAResultPanelProps) { const { seqs } = useMemo(() => parseAlignedFasta(alnFasta), [alnFasta]); const stats = useMemo(() => computeAlignmentStats(seqs), [seqs]); const download = () => { const blob = new Blob([alnFasta], { type: 'text/plain' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `msa-${jobId?.slice(0, 8) ?? 'result'}.fasta`; a.click(); URL.revokeObjectURL(url); }; return (

Multiple Sequence Alignment

{sequenceCount ?? seqs.length} sequences aligned via Clustal Omega {alignmentMode === 'local' && ( local refinement )}

{seqs.length >= 2 && (
)} {pairwise && (

Query vs Top Hit — {pairwise.mode === 'local' ? 'Smith-Waterman (local)' : 'Needleman-Wunsch (global)'}

{pairwise.mode} refinement
)} {phylotree && (

Phylogenetic Tree

)}
); }