99 * by the Apache License, Version 2.0
1010 */
1111
12- import { useQuery } from '@connectrpc/connect-query' ;
12+ import { createConnectQueryKey } from '@connectrpc/connect-query' ;
1313import { Alert , AlertIcon , Button , DataTable , Result , Skeleton } from '@redpanda-data/ui' ;
14+ import { useQuery } from '@tanstack/react-query' ;
1415import { SkipIcon } from 'components/icons' ;
16+ import { config } from 'config' ;
1517import { useMemo } from 'react' ;
1618
1719import {
@@ -20,22 +22,90 @@ import {
2022 Quota_ValueType ,
2123} from '../../../protogen/redpanda/api/dataplane/v1/quota_pb' ;
2224import { listQuotas } from '../../../protogen/redpanda/api/dataplane/v1/quota-QuotaService_connectquery' ;
25+ import type { QuotaResponse , QuotaResponseSetting } from '../../../state/rest-interfaces' ;
2326import { InfoText } from '../../../utils/tsx-utils' ;
2427import { prettyBytes , prettyNumber } from '../../../utils/utils' ;
2528import PageContent from '../../misc/page-content' ;
2629import Section from '../../misc/section' ;
2730
31+ /**
32+ * Maps REST API quota value types to protobuf ValueType enum
33+ */
34+ const mapValueTypeToProto = ( key : string ) : Quota_ValueType => {
35+ switch ( key ) {
36+ case 'producer_byte_rate' :
37+ return Quota_ValueType . PRODUCER_BYTE_RATE ;
38+ case 'consumer_byte_rate' :
39+ return Quota_ValueType . CONSUMER_BYTE_RATE ;
40+ case 'controller_mutation_rate' :
41+ return Quota_ValueType . CONTROLLER_MUTATION_RATE ;
42+ case 'request_percentage' :
43+ return Quota_ValueType . REQUEST_PERCENTAGE ;
44+ default :
45+ return Quota_ValueType . UNSPECIFIED ;
46+ }
47+ } ;
48+
49+ /**
50+ * Maps REST API entity type to protobuf EntityType enum
51+ */
52+ const mapEntityTypeToProto = ( entityType : string ) : Quota_EntityType => {
53+ switch ( entityType ) {
54+ case 'client-id' :
55+ return Quota_EntityType . CLIENT_ID ;
56+ case 'user' :
57+ return Quota_EntityType . USER ;
58+ case 'ip' :
59+ return Quota_EntityType . IP ;
60+ default :
61+ return Quota_EntityType . UNSPECIFIED ;
62+ }
63+ } ;
64+
65+ /**
66+ * Custom hook to fetch quotas from REST API until protobuf endpoint is available
67+ */
68+ const useQuotasQuery = ( ) => {
69+ // Create a query key compatible with Connect Query for future migration
70+ const queryKey = createConnectQueryKey ( {
71+ schema : listQuotas ,
72+ input : { } ,
73+ cardinality : 'finite' ,
74+ } ) ;
75+
76+ return useQuery < QuotaResponse | null > ( {
77+ queryKey,
78+ queryFn : async ( ) => {
79+ const response = await config . fetch ( `${ config . restBasePath } /quotas` , {
80+ method : 'GET' ,
81+ headers : { } ,
82+ } ) ;
83+
84+ if ( ! response . ok ) {
85+ if ( response . status === 403 || response . status === 401 ) {
86+ throw new Error ( 'You do not have permission to view quotas' ) ;
87+ }
88+ throw new Error ( `Failed to fetch quotas: ${ response . statusText } ` ) ;
89+ }
90+
91+ const data : QuotaResponse = await response . json ( ) ;
92+ return data ;
93+ } ,
94+ refetchOnMount : 'always' ,
95+ } ) ;
96+ } ;
97+
2898const QuotasList = ( ) => {
29- const { data, error, isLoading } = useQuery ( listQuotas , { } ) ;
99+ const { data, error, isLoading } = useQuotasQuery ( ) ;
30100
31101 const quotasData = useMemo ( ( ) => {
32- if ( ! data ?. quotas ) {
102+ if ( ! data ?. items ) {
33103 return [ ] ;
34104 }
35105
36- return data . quotas . map ( ( entry ) => {
37- const entityType = entry . entity ?. entityType ;
38- const entityName = entry . entity ? .entityName ;
106+ return data . items . map ( ( item ) => {
107+ const entityType = mapEntityTypeToProto ( item . entityType ) ;
108+ const entityName = item . entityName ;
39109
40110 // Map entity type to display string
41111 let displayType : 'client-id' | 'user' | 'ip' | 'unknown' = 'unknown' ;
@@ -47,11 +117,20 @@ const QuotasList = () => {
47117 displayType = 'ip' ;
48118 }
49119
120+ // Transform REST API settings to protobuf Value format
121+ const values : Quota_Value [ ] = item . settings . map (
122+ ( setting : QuotaResponseSetting ) : Quota_Value => ( {
123+ valueType : mapValueTypeToProto ( setting . key ) ,
124+ value : setting . value ,
125+ $typeName : 'redpanda.api.dataplane.v1.Quota.Value' ,
126+ } )
127+ ) ;
128+
50129 return {
51130 eqKey : `${ entityType } -${ entityName } ` ,
52131 entityType : displayType ,
53132 entityName : entityName || undefined ,
54- values : entry . values ,
133+ values,
55134 } ;
56135 } ) ;
57136 } , [ data ] ) ;
@@ -128,6 +207,19 @@ const QuotasList = () => {
128207 ) ;
129208 }
130209
210+ if ( data ?. error ) {
211+ return (
212+ < PageContent >
213+ < Section >
214+ < Alert status = "warning" style = { { marginBottom : '1em' } } variant = "solid" >
215+ < AlertIcon />
216+ { data . error }
217+ </ Alert >
218+ </ Section >
219+ </ PageContent >
220+ ) ;
221+ }
222+
131223 return (
132224 < PageContent >
133225 < Section >
0 commit comments