ManimCat / frontend /src /studio /components /StudioReviewPanel.tsx
Bin29's picture
Sync from main: 68df783 feat: support multimodal studio reference images
d47b053
import type { StudioWorkResult } from '../protocol/studio-agent-types'
import type { StudioReviewViewModel } from '../store/studio-selectors'
import { studioPanelClass } from '../theme'
import { StudioReviewFindingList } from './StudioReviewFindingList'
import { useI18n } from '../../i18n'
interface StudioReviewPanelProps {
result: StudioWorkResult | null
review: StudioReviewViewModel | null
}
export function StudioReviewPanel({ result, review }: StudioReviewPanelProps) {
const { t } = useI18n()
if (!result || !review) {
return (
<section className={studioPanelClass('p-4')}>
<div className="text-xs uppercase tracking-[0.28em] text-text-secondary">{t('studio.review.title')}</div>
<div className="mt-3 text-sm text-text-secondary">{t('studio.review.empty')}</div>
</section>
)
}
return (
<section className={studioPanelClass('p-4')}>
<div className="text-xs uppercase tracking-[0.28em] text-text-secondary">{t('studio.review.title')}</div>
<h3 className="mt-2 text-lg font-semibold text-text-primary">{result.summary}</h3>
{(review.sourceLabel || review.path) && (
<div className="mt-2 text-xs text-text-secondary">
{review.sourceLabel ?? review.path}
</div>
)}
<div className="mt-4 grid gap-4 xl:grid-cols-[1.1fr_0.9fr]">
<div>
<div className="mb-2 text-sm font-medium text-text-primary">{t('studio.review.findings')}</div>
<StudioReviewFindingList findings={review.findings} />
</div>
<div className="space-y-4">
<div className="rounded-2xl border border-black/10 bg-black/5 p-3 dark:border-white/10 dark:bg-white/5">
<div className="text-sm font-medium text-text-primary">{t('studio.review.summary')}</div>
<div className="mt-2 text-sm text-text-secondary">{review.summary ?? t('studio.review.noSummary')}</div>
</div>
{review.changeSet && (
<div className="rounded-2xl border border-black/10 bg-black/5 p-3 dark:border-white/10 dark:bg-white/5">
<div className="text-sm font-medium text-text-primary">{t('studio.review.changeSet')}</div>
<div className="mt-2 space-y-3 text-xs text-text-secondary">
{review.changeSet.before && <CodeBlock title={t('studio.review.before')} content={review.changeSet.before} />}
{review.changeSet.after && <CodeBlock title={t('studio.review.after')} content={review.changeSet.after} />}
{review.changeSet.diff && <CodeBlock title={t('studio.review.diff')} content={review.changeSet.diff} />}
</div>
</div>
)}
{review.report && <CodeBlock title={t('studio.review.rawReport')} content={review.report} />}
</div>
</div>
</section>
)
}
function CodeBlock({ title, content }: { title: string; content: string }) {
return (
<div>
<div className="mb-1 text-xs uppercase tracking-[0.2em] text-text-secondary">{title}</div>
<pre className="overflow-auto rounded-2xl bg-white/70 p-3 text-xs leading-6 text-text-primary dark:bg-black/20">{content}</pre>
</div>
)
}