/** * * Copyright 2023-2025 InspectorRAGet Team * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * **/ 'use client'; import { useMemo } from 'react'; import { DataTable, TableContainer, Table, TableHead, TableRow, TableHeader, TableBody, TableCell, } from '@carbon/react'; import { Metric, Annotation } from '@/src/types'; import { extractMetricDisplayValue, extractMetricDisplayName, } from '@/src/utilities/metrics'; import classes from './AnnotationsTable.module.scss'; // =================================================================================== // COMPUTE FUNCTIONS // =================================================================================== /** * Helper function to compute annotations table headers and rows * @param annotations full set of annotations * @returns */ function populateTable( annotations: { [key: string]: { [key: string]: Annotation }; }, metrics: Metric[], ) { // Step 0: Metric names const metricNames = metrics.map((metric) => metric.name); // Step 1: Identify headers const headers: { key: string; header: string }[] = [ { key: 'annotator', header: 'Annotator', }, ]; metrics.forEach((metric) => { headers.push({ key: metric.name, header: extractMetricDisplayName(metric), }); }); // Step 2: Build rows // Step 2.a: Collect metrics per annotator const MetricsPerAnnotator: { [key: string]: { [key: string]: string | number }; } = {}; for (const [metricName, annotators] of Object.entries(annotations)) { if (metricNames.includes(metricName)) { for (const [annotator, entry] of Object.entries(annotators)) { if (MetricsPerAnnotator.hasOwnProperty(annotator)) { MetricsPerAnnotator[annotator][metricName] = entry.value; } else { MetricsPerAnnotator[annotator] = { [metricName]: entry.value }; } } } } // Step 2.a: Formulate rows const rows: { [key: string]: any }[] = []; for (const [annotator, metricNames] of Object.entries(MetricsPerAnnotator)) { const row = { id: annotator, annotator: annotator }; for (const [metricName, value] of Object.entries(metricNames)) { row[metricName] = extractMetricDisplayValue( value, metrics.find((metric) => metric.name === metricName)?.values, ); } rows.push(row); } return [headers, rows]; } // =================================================================================== // MAIN FUNCTION // =================================================================================== export default function AnnotationsTable({ annotations, metrics, }: { annotations: { [key: string]: { [key: string]: Annotation }; }; metrics: Metric[]; }) { // Step 1: Run effects // Step 1.a: Populate table header and rows const [headers, rows] = useMemo( () => populateTable(annotations, metrics), [annotations, metrics], ); return ( <> {headers && rows && (