99 * by the Apache License, Version 2.0
1010 */
1111
12- import { Alert , AlertIcon , DataTable } from '@redpanda-data/ui' ;
12+ import {
13+ type ColumnDef ,
14+ flexRender ,
15+ getCoreRowModel ,
16+ getPaginationRowModel ,
17+ getSortedRowModel ,
18+ type PaginationState ,
19+ type SortingState ,
20+ type Updater ,
21+ useReactTable ,
22+ } from '@tanstack/react-table' ;
23+ import { parseAsBoolean , parseAsInteger , parseAsString , useQueryState } from 'nuqs' ;
1324
25+ import { useQueryStateWithCallback } from '../../../../hooks/use-query-state-with-callback' ;
1426import type {
1527 AclRule ,
1628 AclStrOperation ,
@@ -19,91 +31,183 @@ import type {
1931 AclStrResourceType ,
2032 GetAclOverviewResponse ,
2133} from '../../../../state/rest-interfaces' ;
34+ import { uiSettings } from '../../../../state/ui' ;
2235import { toJson } from '../../../../utils/json-utils' ;
36+ import { DEFAULT_TABLE_PAGE_SIZE } from '../../../constants' ;
37+ import { Alert , AlertDescription } from '../../../redpanda-ui/components/alert' ;
38+ import { DataTableColumnHeader , DataTablePagination } from '../../../redpanda-ui/components/data-table' ;
39+ import { Table , TableBody , TableCell , TableHead , TableHeader , TableRow } from '../../../redpanda-ui/components/table' ;
2340
2441type Acls = GetAclOverviewResponse | null | undefined ;
2542
26- type AclListProps = {
27- acl : Acls ;
43+ type AclFlatResource = {
44+ eqKey : string ;
45+ principal : string ;
46+ host : string ;
47+ operation : AclStrOperation ;
48+ permissionType : AclStrPermission ;
49+ resourceType : AclStrResourceType ;
50+ resourceName : string ;
51+ resourcePatternType : AclStrResourcePatternType ;
52+ acls : AclRule [ ] ;
2853} ;
2954
30- function flatResourceList ( store : Acls ) {
31- const acls = store ;
32- if ( ! acls || acls . aclResources === null ) {
55+ function flatResourceList ( store : Acls ) : AclFlatResource [ ] {
56+ if ( ! store || store . aclResources === null ) {
3357 return [ ] ;
3458 }
35- const flatResources = acls . aclResources
59+ return store . aclResources
3660 . flatMap ( ( res ) => res . acls . map ( ( rule ) => ( { ...res , ...rule } ) ) )
3761 . map ( ( x ) => ( { ...x , eqKey : toJson ( x ) } ) ) ;
38- return flatResources ;
3962}
4063
41- export default ( { acl } : AclListProps ) => {
64+ const columns : ColumnDef < AclFlatResource > [ ] = [
65+ {
66+ accessorKey : 'resourceType' ,
67+ header : ( { column } ) => < DataTableColumnHeader column = { column } title = "Resource" /> ,
68+ } ,
69+ {
70+ accessorKey : 'permissionType' ,
71+ header : ( { column } ) => < DataTableColumnHeader column = { column } title = "Permission" /> ,
72+ } ,
73+ {
74+ accessorKey : 'principal' ,
75+ header : ( { column } ) => < DataTableColumnHeader column = { column } title = "Principal" /> ,
76+ } ,
77+ {
78+ accessorKey : 'operation' ,
79+ header : ( { column } ) => < DataTableColumnHeader column = { column } title = "Operation" /> ,
80+ } ,
81+ {
82+ accessorKey : 'resourcePatternType' ,
83+ header : ( { column } ) => < DataTableColumnHeader column = { column } title = "PatternType" /> ,
84+ } ,
85+ {
86+ accessorKey : 'resourceName' ,
87+ header : ( { column } ) => < DataTableColumnHeader column = { column } title = "Name" /> ,
88+ } ,
89+ {
90+ accessorKey : 'host' ,
91+ header : ( { column } ) => < DataTableColumnHeader column = { column } title = "Host" /> ,
92+ } ,
93+ ] ;
94+
95+ const AclList = ( { acl } : { acl : Acls } ) => {
4296 const resources = flatResourceList ( acl ) ;
4397
98+ const [ pageIndex , setPageIndex ] = useQueryState ( 'aclPage' , parseAsInteger . withDefault ( 0 ) ) ;
99+
100+ const [ pageSize , setPageSize ] = useQueryStateWithCallback < number > (
101+ {
102+ onUpdate : ( val ) => {
103+ uiSettings . topicAclList . pageSize = val ;
104+ } ,
105+ getDefaultValue : ( ) => uiSettings . topicAclList . pageSize ,
106+ } ,
107+ 'aclPageSize' ,
108+ parseAsInteger . withDefault ( DEFAULT_TABLE_PAGE_SIZE )
109+ ) ;
110+
111+ const [ sortId , setSortId ] = useQueryStateWithCallback < string > (
112+ {
113+ onUpdate : ( val ) => {
114+ uiSettings . topicAclList . sortId = val ;
115+ } ,
116+ getDefaultValue : ( ) => uiSettings . topicAclList . sortId ,
117+ } ,
118+ 'aclSortId' ,
119+ parseAsString . withDefault ( '' )
120+ ) ;
121+
122+ const [ sortDesc , setSortDesc ] = useQueryStateWithCallback < boolean > (
123+ {
124+ onUpdate : ( val ) => {
125+ uiSettings . topicAclList . sortDesc = val ;
126+ } ,
127+ getDefaultValue : ( ) => uiSettings . topicAclList . sortDesc ,
128+ } ,
129+ 'aclSortDesc' ,
130+ parseAsBoolean . withDefault ( false )
131+ ) ;
132+
133+ const sorting : SortingState = sortId ? [ { id : sortId , desc : sortDesc } ] : [ ] ;
134+ const pagination : PaginationState = { pageIndex, pageSize } ;
135+
136+ const handleSortingChange = ( updater : Updater < SortingState > ) => {
137+ const next = typeof updater === 'function' ? updater ( sorting ) : updater ;
138+ if ( next . length > 0 ) {
139+ setSortId ( next [ 0 ] . id ) ;
140+ setSortDesc ( next [ 0 ] . desc ) ;
141+ } else {
142+ setSortId ( '' ) ;
143+ setSortDesc ( false ) ;
144+ }
145+ void setPageIndex ( 0 ) ;
146+ } ;
147+
148+ const handlePaginationChange = ( updater : Updater < PaginationState > ) => {
149+ const next = typeof updater === 'function' ? updater ( pagination ) : updater ;
150+ void setPageIndex ( next . pageIndex ) ;
151+ setPageSize ( next . pageSize ) ;
152+ } ;
153+
154+ const table = useReactTable ( {
155+ data : resources ,
156+ columns,
157+ state : { sorting, pagination } ,
158+ onSortingChange : handleSortingChange ,
159+ onPaginationChange : handlePaginationChange ,
160+ getCoreRowModel : getCoreRowModel ( ) ,
161+ getSortedRowModel : getSortedRowModel ( ) ,
162+ getPaginationRowModel : getPaginationRowModel ( ) ,
163+ autoResetPageIndex : false ,
164+ } ) ;
165+
44166 return (
45167 < >
46- { acl === null ? (
47- < Alert status = "warning" style = { { marginBottom : '1em' } } >
48- < AlertIcon />
49- You do not have the necessary permissions to view ACLs
168+ { acl === null && (
169+ < Alert className = "mb-4" variant = "warning" >
170+ < AlertDescription > You do not have the necessary permissions to view ACLs</ AlertDescription >
50171 </ Alert >
51- ) : null }
52- { acl ?. isAuthorizerEnabled ? null : (
53- < Alert status = "warning" style = { { marginBottom : '1em' } } >
54- < AlertIcon />
55- There's no authorizer configured in your Kafka cluster
172+ ) }
173+ { acl ?. isAuthorizerEnabled === false && (
174+ < Alert className = "mb-4" variant = "warning" >
175+ < AlertDescription > There's no authorizer configured in your Kafka cluster</ AlertDescription >
56176 </ Alert >
57177 ) }
58- < DataTable < {
59- eqKey : string ;
60- principal : string ;
61- host : string ;
62- operation : AclStrOperation ;
63- permissionType : AclStrPermission ;
64- resourceType : AclStrResourceType ;
65- resourceName : string ;
66- resourcePatternType : AclStrResourcePatternType ;
67- acls : AclRule [ ] ;
68- } >
69- columns = { [
70- {
71- size : 120 ,
72- header : 'Resource' ,
73- accessorKey : 'resourceType' ,
74- } ,
75- {
76- size : 120 ,
77- header : 'Permission' ,
78- accessorKey : 'permissionType' ,
79- } ,
80- {
81- header : 'Principal' ,
82- accessorKey : 'principal' ,
83- } ,
84- {
85- size : 160 ,
86- header : 'Operation' ,
87- accessorKey : 'operation' ,
88- } ,
89- {
90- header : 'PatternType' ,
91- accessorKey : 'resourcePatternType' ,
92- } ,
93- {
94- header : 'Name' ,
95- accessorKey : 'resourceName' ,
96- } ,
97- {
98- size : 120 ,
99- header : 'Host' ,
100- accessorKey : 'host' ,
101- } ,
102- ] }
103- data = { resources }
104- pagination
105- sorting
106- />
178+ < Table >
179+ < TableHeader >
180+ { table . getHeaderGroups ( ) . map ( ( headerGroup ) => (
181+ < TableRow key = { headerGroup . id } >
182+ { headerGroup . headers . map ( ( header ) => (
183+ < TableHead key = { header . id } >
184+ { header . isPlaceholder ? null : flexRender ( header . column . columnDef . header , header . getContext ( ) ) }
185+ </ TableHead >
186+ ) ) }
187+ </ TableRow >
188+ ) ) }
189+ </ TableHeader >
190+ < TableBody >
191+ { table . getRowModel ( ) . rows . length === 0 ? (
192+ < TableRow >
193+ < TableCell className = "text-center" colSpan = { columns . length } >
194+ No data found
195+ </ TableCell >
196+ </ TableRow >
197+ ) : (
198+ table . getRowModel ( ) . rows . map ( ( row ) => (
199+ < TableRow key = { row . id } >
200+ { row . getVisibleCells ( ) . map ( ( cell ) => (
201+ < TableCell key = { cell . id } > { flexRender ( cell . column . columnDef . cell , cell . getContext ( ) ) } </ TableCell >
202+ ) ) }
203+ </ TableRow >
204+ ) )
205+ ) }
206+ </ TableBody >
207+ </ Table >
208+ < DataTablePagination table = { table } />
107209 </ >
108210 ) ;
109211} ;
212+
213+ export default AclList ;
0 commit comments