1
1
'use client' ;
2
2
3
- import { Table , Badge , Button } from '@mantine/core' ;
3
+ import { Badge , Button } from '@mantine/core' ;
4
4
import { useQuery } from '@tanstack/react-query' ;
5
5
import _compact from 'lodash-es/compact' ;
6
6
import _get from 'lodash-es/get' ;
7
- import { JSX , ReactNode } from 'react' ;
7
+ import { useMemo } from 'react' ;
8
8
import DataTable from '@/components/generic/data-table/DataTable' ;
9
+ import type { ColumnDefinition } from '@/components/generic/data-table/DataTable' ;
9
10
import { GlobalRole } from '@/constants' ;
10
11
import createClientPage from '@/core/client-page' ;
11
12
import { listKeycloakTeamApiAccounts } from '@/services/backend/keycloak' ;
@@ -21,83 +22,10 @@ interface TeamApiAccount {
21
22
secret : string ;
22
23
}
23
24
24
- interface ColumnDef {
25
- label ?: string ;
26
- value : string ;
27
- cellProcessor : ( account : TeamApiAccount , attr : string ) => React . ReactNode ;
28
- }
29
-
30
25
const TeamApiAccountsPage = createClientPage ( {
31
26
roles : [ GlobalRole . User ] ,
32
27
} ) ;
33
28
export default TeamApiAccountsPage ( ( { session } ) => {
34
- const teamApiAccountData : TeamApiAccount [ ] = [ ] ;
35
- const tableColumns : ColumnDef [ ] = [
36
- {
37
- label : 'Name' ,
38
- value : 'name' ,
39
- cellProcessor : ( account , attr ) => (
40
- < span className = "whitespace-nowrap" >
41
- { account . name } { ' ' }
42
- < Badge color = "green" radius = "sm" className = "ml-1" >
43
- Active
44
- </ Badge >
45
- </ span >
46
- ) ,
47
- } ,
48
- {
49
- label : 'Roles' ,
50
- value : 'roles' ,
51
- cellProcessor : ( account , attr ) => (
52
- < >
53
- { account . roles . map ( ( role ) => (
54
- < Badge key = { role } color = "gray" radius = "sm" className = "mr-1" >
55
- { role }
56
- </ Badge >
57
- ) ) }
58
- </ >
59
- ) ,
60
- } ,
61
- {
62
- label : '' ,
63
- value : 'actionButtons' ,
64
- cellProcessor : ( account , attr ) => (
65
- < >
66
- < Button
67
- className = "mr-1"
68
- variant = "outline"
69
- onClick = { async ( ) => {
70
- await openViewAccountModal ( {
71
- clientUid : account . id ,
72
- clientId : account . clientId ,
73
- clientSecret : account . secret ,
74
- name : account . name ,
75
- roles : account . roles ,
76
- } ) ;
77
- } }
78
- >
79
- View
80
- </ Button >
81
- { session ?. isAdmin && (
82
- < Button
83
- variant = "outline"
84
- onClick = { async ( ) => {
85
- await openManageAccountModal ( {
86
- clientUid : account . id ,
87
- roles : account . roles ,
88
- name : account . name ?? '' ,
89
- } ) ;
90
- await refetchApiAccounts ( ) ;
91
- } }
92
- >
93
- Manage
94
- </ Button >
95
- ) }
96
- </ >
97
- ) ,
98
- } ,
99
- ] ;
100
-
101
29
const {
102
30
data : apiAccounts ,
103
31
isLoading : isApiAccountsLoading ,
@@ -109,40 +37,101 @@ export default TeamApiAccountsPage(({ session }) => {
109
37
queryFn : ( ) => listKeycloakTeamApiAccounts ( ) ,
110
38
} ) ;
111
39
112
- if ( isApiAccountsLoading ) {
113
- return null ;
114
- }
40
+ const { data : tableData , columns : tableColumns } = useMemo ( ( ) => {
41
+ if ( ! apiAccounts ) return { data : [ ] , columns : [ ] } ;
115
42
116
- let rows : ReactNode = null ;
117
- if ( ! apiAccounts || apiAccounts . length === 0 ) {
118
- const message = session ?. isAdmin ? 'No team API accounts found.' : 'You are not assigned to any team API accounts.' ;
43
+ const _columns : ColumnDefinition < TeamApiAccount > [ ] = [
44
+ {
45
+ label : 'Name' ,
46
+ value : 'name' ,
47
+ cellProcessor : ( account , attr ) => (
48
+ < span className = "whitespace-nowrap" >
49
+ { account . name } { ' ' }
50
+ < Badge color = "green" radius = "sm" className = "ml-1" >
51
+ Active
52
+ </ Badge >
53
+ </ span >
54
+ ) ,
55
+ } ,
56
+ {
57
+ label : 'Roles' ,
58
+ value : 'roles' ,
59
+ cellProcessor : ( account , attr ) => (
60
+ < >
61
+ { account . roles . map ( ( role ) => (
62
+ < Badge key = { role } color = "gray" radius = "sm" className = "mr-1" >
63
+ { role }
64
+ </ Badge >
65
+ ) ) }
66
+ </ >
67
+ ) ,
68
+ } ,
69
+ {
70
+ label : '' ,
71
+ value : 'actionButtons' ,
72
+ cellProcessor : ( account , attr ) => (
73
+ < >
74
+ < Button
75
+ className = "mr-1"
76
+ variant = "outline"
77
+ onClick = { async ( ) => {
78
+ await openViewAccountModal ( {
79
+ clientUid : account . id ,
80
+ clientId : account . clientId ,
81
+ clientSecret : account . secret ,
82
+ name : account . name ,
83
+ roles : account . roles ,
84
+ } ) ;
85
+ } }
86
+ >
87
+ View
88
+ </ Button >
89
+ { session ?. isAdmin && (
90
+ < Button
91
+ variant = "outline"
92
+ onClick = { async ( ) => {
93
+ await openManageAccountModal ( {
94
+ clientUid : account . id ,
95
+ roles : account . roles ,
96
+ name : account . name ?? '' ,
97
+ } ) ;
98
+ await refetchApiAccounts ( ) ;
99
+ } }
100
+ >
101
+ Manage
102
+ </ Button >
103
+ ) }
104
+ </ >
105
+ ) ,
106
+ } ,
107
+ ] ;
119
108
120
- rows = (
121
- < Table . Tr >
122
- < Table . Td colSpan = { 3 } > { message } </ Table . Td >
123
- </ Table . Tr >
124
- ) ;
125
- } else {
126
- ( apiAccounts ?? [ ] ) . forEach ( ( account ) => {
109
+ const _data : TeamApiAccount [ ] = ( apiAccounts ?? [ ] ) . map ( ( account ) => {
127
110
const rolesMapper = account . protocolMappers ?. find ( ( mapper ) => mapper . name === 'roles' ) ;
128
111
const rolesStr = _get ( rolesMapper , [ 'config' , 'claim.value' ] , '' ) ;
129
112
130
- teamApiAccountData . push ( {
131
- name : account . name ! ,
113
+ return {
114
+ name : account . name ?? '' ,
132
115
roles : _compact ( rolesStr . split ( ',' ) ) ,
133
- id : account . id ! ,
134
- clientId : account . clientId ! ,
135
- secret : account . secret ! ,
136
- } ) ;
116
+ id : account . id ?? '' ,
117
+ clientId : account . clientId ?? '' ,
118
+ secret : account . secret ?? '' ,
119
+ } ;
137
120
} ) ;
121
+
122
+ return { data : _data , columns : _columns } ;
123
+ } , [ session , apiAccounts ] ) ;
124
+
125
+ if ( isApiAccountsLoading ) {
126
+ return null ;
138
127
}
139
128
140
129
return (
141
130
< div className = "pt-5" >
142
- < h1 className = "text-xl lg:text-2xl 2xl:text-4xl font-semibold leading-7 text-gray-900 pb-2 " > Team API Accounts</ h1 >
131
+ < h1 className = "text-xl lg:text-2xl 2xl:text-4xl font-semibold leading-7 text-gray-900" > Team API Accounts</ h1 >
143
132
144
133
{ session ?. isAdmin && (
145
- < div className = "text-right mb-11 " >
134
+ < div className = "text-right mb-2 " >
146
135
< Button
147
136
color = "blue"
148
137
onClick = { async ( ) => {
@@ -154,7 +143,7 @@ export default TeamApiAccountsPage(({ session }) => {
154
143
</ Button >
155
144
</ div >
156
145
) }
157
- < DataTable < TeamApiAccount > data = { teamApiAccountData } columns = { tableColumns } />
146
+ < DataTable < TeamApiAccount > data = { tableData } columns = { tableColumns } />
158
147
</ div >
159
148
) ;
160
149
} ) ;
0 commit comments