1+ import React from "react" ;
2+ const jsonData = import . meta. glob ( '/src/data/coverage/*.json' ) ;
3+ import {
4+ Table ,
5+ TableHeader ,
6+ TableBody ,
7+ TableRow ,
8+ TableHead ,
9+ TableCell ,
10+ } from "@/components/ui/table" ;
11+ import {
12+ useReactTable ,
13+ getCoreRowModel ,
14+ getSortedRowModel ,
15+ flexRender ,
16+ getFilteredRowModel ,
17+ getPaginationRowModel ,
18+ } from "@tanstack/react-table" ;
19+ import type { SortingState , ColumnDef , ColumnFiltersState } from "@tanstack/react-table" ;
20+
21+ const columns : ColumnDef < any > [ ] = [
22+ {
23+ accessorKey : "full_name" ,
24+ header : ( ) => "Service" ,
25+ cell : ( { row } ) => (
26+ < a href = { `/aws/${ row . original . service } ` } > { row . original . full_name } </ a >
27+ ) ,
28+ enableColumnFilter : true ,
29+ filterFn : ( row , columnId , filterValue ) => {
30+ return row . original . full_name
31+ . toLowerCase ( )
32+ . includes ( ( filterValue ?? "" ) . toLowerCase ( ) ) ;
33+ } ,
34+ meta : { className : "w-1/3" } ,
35+ } ,
36+ {
37+ accessorKey : "support" ,
38+ header : ( ) => "Supported" ,
39+ cell : ( { row } ) =>
40+ row . original . support === "supported" ||
41+ row . original . support === "supported with limitations"
42+ ? "✔️"
43+ : "" ,
44+ meta : { className : "w-1/6" } ,
45+ enableSorting : true ,
46+ sortingFn : ( rowA , rowB ) => {
47+ // Sort supported to the top
48+ const a = rowA . original . support ;
49+ const b = rowB . original . support ;
50+ if ( a === b ) return 0 ;
51+ if ( a === "supported" ) return - 1 ;
52+ if ( b === "supported" ) return 1 ;
53+ if ( a === "supported with limitations" ) return - 1 ;
54+ if ( b === "supported with limitations" ) return 1 ;
55+ return a . localeCompare ( b ) ;
56+ } ,
57+ } ,
58+ {
59+ accessorKey : "test_suite" ,
60+ header : ( ) => "Persistence Test Suite" ,
61+ cell : ( { row } ) => ( row . original . test_suite ? "✔️" : "" ) ,
62+ meta : { className : "w-1/6" } ,
63+ enableSorting : true ,
64+ } ,
65+ {
66+ accessorKey : "limitations" ,
67+ header : ( ) => "Limitations" ,
68+ cell : ( { row } ) => row . original . limitations ,
69+ enableSorting : false ,
70+ meta : { className : "whitespace-normal" } ,
71+ } ,
72+ ] ;
73+
74+ export default function PersistenceCoverage ( { service} : { service : string } ) {
75+ const data = jsonData [ `/src/data/coverage/${ service } .json` ] ;
76+ const coverage = Object . values ( data ) ;
77+ const [ sorting , setSorting ] = React . useState < SortingState > ( [
78+ { id : "full_name" , desc : false } ,
79+ ] ) ;
80+ const [ columnFilters , setColumnFilters ] = React . useState < ColumnFiltersState > ( [ ] ) ;
81+
82+ const table = useReactTable ( {
83+ data : coverage ,
84+ columns,
85+ state : { sorting, columnFilters } ,
86+ onSortingChange : setSorting ,
87+ onColumnFiltersChange : setColumnFilters ,
88+ getCoreRowModel : getCoreRowModel ( ) ,
89+ getSortedRowModel : getSortedRowModel ( ) ,
90+ getFilteredRowModel : getFilteredRowModel ( ) ,
91+ getPaginationRowModel : getPaginationRowModel ( ) ,
92+ debugTable : false ,
93+ initialState : { pagination : { pageSize : 10 } } ,
94+ } ) ;
95+
96+ return (
97+ < div className = "w-full" >
98+ < h2 id = "api-coverage" > API Coverage</ h2 >
99+ < div style = { { marginBottom : 12 , marginTop : 12 } } >
100+ < input
101+ type = "text"
102+ placeholder = "Filter by service name..."
103+ value = {
104+ table . getColumn ( "full_name" ) ?. getFilterValue ( ) as string || ""
105+ }
106+ onChange = { e =>
107+ table . getColumn ( "full_name" ) ?. setFilterValue ( e . target . value )
108+ }
109+ className = "border rounded px-2 py-1 w-full max-w-xs"
110+ />
111+ </ div >
112+ < div className = "rounded-md border" >
113+ < Table >
114+ < TableHeader >
115+ { table . getHeaderGroups ( ) . map ( ( headerGroup ) => (
116+ < TableRow key = { headerGroup . id } >
117+ { headerGroup . headers . map ( ( header ) => {
118+ const canSort = header . column . getCanSort ( ) ;
119+ const meta = header . column . columnDef . meta as { className ?: string } | undefined ;
120+ return (
121+ < TableHead
122+ key = { header . id }
123+ onClick = { canSort ? header . column . getToggleSortingHandler ( ) : undefined }
124+ className = {
125+ ( meta ?. className || "" ) +
126+ ( canSort ? " cursor-pointer select-none" : "" )
127+ }
128+ >
129+ { flexRender ( header . column . columnDef . header , header . getContext ( ) ) }
130+ { canSort && (
131+ < span >
132+ { header . column . getIsSorted ( ) === "asc"
133+ ? " ▲"
134+ : header . column . getIsSorted ( ) === "desc"
135+ ? " ▼"
136+ : "" }
137+ </ span >
138+ ) }
139+ </ TableHead >
140+ ) ;
141+ } ) }
142+ </ TableRow >
143+ ) ) }
144+ </ TableHeader >
145+ < TableBody >
146+ { table . getRowModel ( ) . rows . map ( ( row ) => (
147+ < TableRow key = { row . id } >
148+ { row . getVisibleCells ( ) . map ( ( cell ) => {
149+ const meta = cell . column . columnDef . meta as { className ?: string } | undefined ;
150+ return (
151+ < TableCell
152+ key = { cell . id }
153+ className = { meta ?. className || undefined }
154+ >
155+ { flexRender ( cell . column . columnDef . cell , cell . getContext ( ) ) }
156+ </ TableCell >
157+ ) ;
158+ } ) }
159+ </ TableRow >
160+ ) ) }
161+ </ TableBody >
162+ </ Table >
163+ </ div >
164+ < div className = "flex items-center justify-between mt-4" >
165+ < button
166+ className = "px-3 py-1 border rounded disabled:opacity-50"
167+ onClick = { ( ) => table . previousPage ( ) }
168+ disabled = { ! table . getCanPreviousPage ( ) }
169+ >
170+ Previous
171+ </ button >
172+ < span >
173+ Page { table . getState ( ) . pagination . pageIndex + 1 } of { table . getPageCount ( ) }
174+ </ span >
175+ < button
176+ className = "px-3 py-1 border rounded disabled:opacity-50"
177+ onClick = { ( ) => table . nextPage ( ) }
178+ disabled = { ! table . getCanNextPage ( ) }
179+ >
180+ Next
181+ </ button >
182+ </ div >
183+ </ div >
184+ ) ;
185+ }
0 commit comments