| 1 | <template> |
| 2 | <n-card size="small" title="Per-template performance" embedded> |
| 3 | <n-empty v-if="!stats.per_template.length" description="No reviews yet" class="min-h-20 justify-center" /> |
| 4 | <n-data-table |
| 5 | v-else |
| 6 | :columns="perTemplateColumns" |
| 7 | :data="stats.per_template" |
| 8 | size="small" |
| 9 | :row-key="(r: ReviewStatsTemplate) => r.template_used ?? '__null__'" |
| 10 | /> |
| 11 | </n-card> |
| 12 | </template> |
| 13 | |
| 14 | <script setup lang="tsx"> |
| 15 | import type { DataTableColumns } from "naive-ui" |
| 16 | import type { AiAnalystReviewStats, ReviewStatsTemplate } from "@/types/aiAnalyst.d" |
| 17 | import { NCard, NDataTable, NEmpty } from "naive-ui" |
| 18 | import { computed, toRefs } from "vue" |
| 19 | |
| 20 | const props = defineProps<{ |
| 21 | stats: AiAnalystReviewStats |
| 22 | }>() |
| 23 | |
| 24 | const { stats } = toRefs(props) |
| 25 | |
| 26 | const perTemplateColumns = computed<DataTableColumns<ReviewStatsTemplate>>(() => [ |
| 27 | { |
| 28 | title: "Template", |
| 29 | key: "template_used", |
| 30 | minWidth: 200, |
| 31 | render: row => <div class="min-w-40">{row.template_used ?? "(none)"}</div> |
| 32 | }, |
| 33 | { title: "Total", key: "total", width: 80, render: row => <div class="min-w-14">{row.total}</div> }, |
| 34 | { |
| 35 | title: "Up / Down", |
| 36 | key: "verdict", |
| 37 | width: 110, |
| 38 | render: row => ( |
| 39 | <div class="min-w-18"> |
| 40 | {row.thumbs_up} |
| 41 | {" / "} |
| 42 | {row.thumbs_down} |
| 43 | </div> |
| 44 | ) |
| 45 | }, |
| 46 | { |
| 47 | title: "C / P / W", |
| 48 | key: "choice", |
| 49 | width: 110, |
| 50 | render: row => ( |
| 51 | <div class="min-w-22"> |
| 52 | {row.correct} |
| 53 | {" / "} |
| 54 | {row.partial} |
| 55 | {" / "} |
| 56 | {row.wrong} |
| 57 | </div> |
| 58 | ) |
| 59 | }, |
| 60 | { |
| 61 | title: "Instr", |
| 62 | key: "avg_rating_instructions", |
| 63 | width: 80, |
| 64 | render: row => ( |
| 65 | <div class="min-w-14"> |
| 66 | {row.avg_rating_instructions == null ? "—" : row.avg_rating_instructions.toFixed(2)} |
| 67 | </div> |
| 68 | ) |
| 69 | }, |
| 70 | { |
| 71 | title: "Artif", |
| 72 | key: "avg_rating_artifacts", |
| 73 | width: 80, |
| 74 | render: row => ( |
| 75 | <div class="min-w-14">{row.avg_rating_artifacts == null ? "—" : row.avg_rating_artifacts.toFixed(2)}</div> |
| 76 | ) |
| 77 | }, |
| 78 | { |
| 79 | title: "Sev", |
| 80 | key: "avg_rating_severity", |
| 81 | width: 80, |
| 82 | render: row => ( |
| 83 | <div class="min-w-14">{row.avg_rating_severity == null ? "—" : row.avg_rating_severity.toFixed(2)}</div> |
| 84 | ) |
| 85 | } |
| 86 | ]) |
| 87 | </script> |