Describe the tables as TanStack columns
Add ui/DataTable, which builds ReUI's DataGrid from `columns` and `data`, and move all 23 tables onto it. What the grid does not take (a class on a row or cell, `aria-sort`, `style`, `colSpan`, `role`, `hidden`) is put on the elements it drew after every render. The column definitions keep their identity between renders, so cells are not mounted again, and the grid's own paging is off. The stacked rows on a phone, the column labels and the sort order of the original work as before. In Blocking > Lists a group heading is a row whose first cell spans the four columns. docs/reui-migration-plan.md records it. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
f3531c64f9
commit
4c0a5de7e7
24 files changed
+1611
-1175
No files matched your search
@@ -21,7 +21,7 @@ import { toIso, dateTime } from './dates'
|
||||
import { Loading } from '../../ui/Empty'
|
||||
import { Check } from '../../ui/Check'
|
||||
import { Tag } from '../../ui/Tag'
|
||||
import { Table } from '../../ui/Table'
|
||||
import { DataTable } from '../../ui/DataTable'
|
||||
import styles from './Logs.module.css'
|
||||
import { pageWindow } from '../../lib/pagination'
|
||||
import { Pagination } from '../../ui/Pagination'
|
||||
@@ -927,53 +927,82 @@ export function QueryLogs({ tabs, token, node = '', request }: QueryLogsProps) {
|
||||
{/* Always all seven, whether or not they appear on this page: see `LEGEND_ROWS`. */}
|
||||
<RowLegend fold={fold} />
|
||||
|
||||
<Table
|
||||
<DataTable
|
||||
data={page.entries}
|
||||
getRowId={(e) => String(e.rowNumber)}
|
||||
rowProps={(e) => ({ className: rowClass(e) })}
|
||||
stack
|
||||
tableClass={styles.queryTable}
|
||||
header={
|
||||
<>
|
||||
<th>#</th>
|
||||
<th>Timestamp</th>
|
||||
<th>Client IP Address</th>
|
||||
<th>Protocol</th>
|
||||
<th>Response Type</th>
|
||||
<th>RCODE</th>
|
||||
<th>Domain</th>
|
||||
<th>Type</th>
|
||||
<th>Class</th>
|
||||
<th>Answer</th>
|
||||
<th className={tbl.actionsCell} />
|
||||
</>
|
||||
}
|
||||
>
|
||||
{page.entries.map((e) => (
|
||||
<tr key={e.rowNumber} className={rowClass(e)}>
|
||||
<td className={styles.mono}>{e.rowNumber}</td>
|
||||
<td className={`${styles.mono} ${styles.stamp}`}>
|
||||
<Stamp text={dateTime(e.timestamp)} />
|
||||
</td>
|
||||
<td className={styles.mono}>
|
||||
<Clip text={e.clientIpAddress} className={styles.clipClient} />
|
||||
</td>
|
||||
<td>{e.protocol}</td>
|
||||
<td>
|
||||
columns={[
|
||||
{
|
||||
id: 'c0',
|
||||
header: '#',
|
||||
td: () => ({ className: styles.mono }),
|
||||
cell: (e) => e.rowNumber,
|
||||
},
|
||||
{
|
||||
id: 'c1',
|
||||
header: 'Timestamp',
|
||||
td: () => ({ className: `${styles.mono} ${styles.stamp}` }),
|
||||
cell: (e) => (<Stamp text={dateTime(e.timestamp)} />),
|
||||
},
|
||||
{
|
||||
id: 'c2',
|
||||
header: 'Client IP Address',
|
||||
td: () => ({ className: styles.mono }),
|
||||
cell: (e) => (<Clip text={e.clientIpAddress} className={styles.clipClient} />),
|
||||
},
|
||||
{
|
||||
id: 'c3',
|
||||
header: 'Protocol',
|
||||
cell: (e) => e.protocol,
|
||||
},
|
||||
{
|
||||
id: 'c4',
|
||||
header: 'Response Type',
|
||||
cell: (e) => (
|
||||
<>
|
||||
{/* The row's colour, in this cell: see `.tone` in Logs.module.css. */}
|
||||
<span className={styles.tone}>{e.responseType}</span>
|
||||
{e.responseRtt != null && (
|
||||
<div className={styles.rtt}>({e.responseRtt.toFixed(2)} ms)</div>
|
||||
)}
|
||||
</td>
|
||||
<td>{e.rcode}</td>
|
||||
{/* logs.js:518. The root is written with a dot. */}
|
||||
<td className={`${styles.mono} ${tbl.lead}`}>
|
||||
<Clip text={e.qname === '' ? '.' : (e.qname ?? '')} className={styles.clipDomain} />
|
||||
</td>
|
||||
<td className={tbl.lead}>{e.qtype ?? ''}</td>
|
||||
<td>{e.qclass ?? ''}</td>
|
||||
<td className={`${styles.mono} ${styles.answer}`}>
|
||||
<Clip text={e.answer ?? ''} className={styles.clipAnswer} />
|
||||
</td>
|
||||
<td className={tbl.actionsCell}>
|
||||
<span className={styles.tone}>{e.responseType}</span>
|
||||
{e.responseRtt != null && (
|
||||
<div className={styles.rtt}>({e.responseRtt.toFixed(2)} ms)</div>
|
||||
)}
|
||||
</>
|
||||
),
|
||||
},
|
||||
{
|
||||
id: 'c5',
|
||||
header: 'RCODE',
|
||||
cell: (e) => e.rcode,
|
||||
},
|
||||
{
|
||||
id: 'c6',
|
||||
header: 'Domain',
|
||||
td: () => ({ className: `${styles.mono} ${tbl.lead}` }),
|
||||
cell: (e) => (<Clip text={e.qname === '' ? '.' : (e.qname ?? '')} className={styles.clipDomain} />),
|
||||
},
|
||||
{
|
||||
id: 'c7',
|
||||
header: 'Type',
|
||||
td: () => ({ className: tbl.lead }),
|
||||
cell: (e) => e.qtype ?? '',
|
||||
},
|
||||
{
|
||||
id: 'c8',
|
||||
header: 'Class',
|
||||
cell: (e) => e.qclass ?? '',
|
||||
},
|
||||
{
|
||||
id: 'c9',
|
||||
header: 'Answer',
|
||||
td: () => ({ className: `${styles.mono} ${styles.answer}` }),
|
||||
cell: (e) => (<Clip text={e.answer ?? ''} className={styles.clipAnswer} />),
|
||||
},
|
||||
{
|
||||
id: 'c10',
|
||||
th: { className: tbl.actionsCell },
|
||||
td: () => ({ className: tbl.actionsCell }),
|
||||
cell: (e) => (
|
||||
<Menu label={`Actions for row ${e.rowNumber}`}>
|
||||
{(close) => {
|
||||
const verb = verbFor(e.responseType)
|
||||
@@ -1008,10 +1037,10 @@ export function QueryLogs({ tabs, token, node = '', request }: QueryLogsProps) {
|
||||
)
|
||||
}}
|
||||
</Menu>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</Table>
|
||||
),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
<div className={styles.count}>
|
||||
<span>{statusText(page)}</span>
|
||||
|
||||
Reference in new issue
Block a user