Assessor_2.0/src/components/DataTable/DataTable.tsx

55 lines
2.3 KiB
TypeScript

import { useState } from 'react';
import type { DatasetSheet } from '../../domain/dataset';
import type { FindingRecord } from '../../domain/finding';
import { highlightText } from '../HighlightText/highlight-text';
import { useVirtualRows } from '../../hooks/use-virtual-rows';
interface Props {
sheet: DatasetSheet;
records: FindingRecord[];
search?: string;
}
/**
* Geschaetzte Zeilenhoehe, nur fuer die Fenstermathematik - siehe
* `RECORD_ROW_HEIGHT` in DatasetViewer.tsx fuer die gleiche Ueberlegung.
* Groesser als die Kartenzeile, weil einzelne Spalten (Description,
* Likelihood of Compromise) auch bei einer Rasterzeile umbrechen koennen.
*/
const TABLE_ROW_HEIGHT = 44;
export function DataTable({ sheet, records, search }: Props) {
const [markedRecordId, setMarkedRecordId] = useState<string | null>(null);
const rowWindow = useVirtualRows(records.length, TABLE_ROW_HEIGHT, 12);
const columnCount = sheet.analysis.headers.length + 1;
// Berechnete Geometrie der Virtualisierung als benannte Werte statt eines
// literalen Inline-Style-Objekts - siehe DatasetViewer.tsx fuer dieselbe
// Begruendung.
const topSpacerStyle = { height: rowWindow.paddingTop, padding: 0, border: 0 };
const bottomSpacerStyle = { height: rowWindow.paddingBottom, padding: 0, border: 0 };
return (
<div className="table-scroll" ref={rowWindow.containerRef}>
<table>
<thead>
<tr>
<th className="row-index">#</th>
{sheet.analysis.headers.map(header => <th key={header}>{highlightText(header, search)}</th>)}
</tr>
</thead>
<tbody>
{rowWindow.paddingTop > 0 && <tr aria-hidden="true"><td colSpan={columnCount} style={topSpacerStyle} /></tr>}
{records.slice(rowWindow.startIndex, rowWindow.endIndex).map(record => (
<tr key={record.id} data-row-marked={markedRecordId === record.id ? 'true' : undefined}
onClick={() => setMarkedRecordId(record.id)}>
<td className="row-index">{record.index + 1}</td>
{record.fields.map(field => <td key={`${record.id}-${field.index}`}>{highlightText(field.value, search)}</td>)}
</tr>
))}
{rowWindow.paddingBottom > 0 && <tr aria-hidden="true"><td colSpan={columnCount} style={bottomSpacerStyle} /></tr>}
</tbody>
</table>
</div>
);
}