@@ -9,10 +9,10 @@ import { useLocation } from "react-router";
9
9
import { getCurrentTeam , TeamsContext } from "./teams-context" ;
10
10
import { getGitpodService , gitpodHostUrl } from "../service/service" ;
11
11
import {
12
- BillableSessionRequest ,
12
+ ListBilledUsageRequest ,
13
13
BillableWorkspaceType ,
14
14
ExtendedBillableSession ,
15
- SortOrder ,
15
+ ListBilledUsageResponse ,
16
16
} from "@gitpod/gitpod-protocol/lib/usage" ;
17
17
import { AttributionId } from "@gitpod/gitpod-protocol/lib/attribution" ;
18
18
import { Item , ItemField , ItemsList } from "../components/ItemsList" ;
@@ -21,7 +21,6 @@ import Header from "../components/Header";
21
21
import { ErrorCodes } from "@gitpod/gitpod-protocol/lib/messaging/error" ;
22
22
import { ReactComponent as CreditsSvg } from "../images/credits.svg" ;
23
23
import { ReactComponent as Spinner } from "../icons/Spinner.svg" ;
24
- import { ReactComponent as SortArrow } from "../images/sort-arrow.svg" ;
25
24
import { ReactComponent as UsageIcon } from "../images/usage-default.svg" ;
26
25
import { BillingMode } from "@gitpod/gitpod-protocol/lib/billing-mode" ;
27
26
import { toRemoteURL } from "../projects/render-utils" ;
@@ -31,17 +30,15 @@ function TeamUsage() {
31
30
const location = useLocation ( ) ;
32
31
const team = getCurrentTeam ( location , teams ) ;
33
32
const [ teamBillingMode , setTeamBillingMode ] = useState < BillingMode | undefined > ( undefined ) ;
34
- const [ billedUsage , setBilledUsage ] = useState < ExtendedBillableSession [ ] > ( [ ] ) ;
35
- const [ currentPage , setCurrentPage ] = useState ( 1 ) ;
36
- const [ resultsPerPage ] = useState ( 50 ) ;
33
+ const [ usagePage , setUsagePage ] = useState < ListBilledUsageResponse | undefined > ( undefined ) ;
37
34
const [ errorMessage , setErrorMessage ] = useState ( "" ) ;
38
35
const today = new Date ( ) ;
39
36
const startOfCurrentMonth = new Date ( today . getFullYear ( ) , today . getMonth ( ) , 1 ) ;
40
37
const timestampStartOfCurrentMonth = startOfCurrentMonth . getTime ( ) ;
41
38
const [ startDateOfBillMonth , setStartDateOfBillMonth ] = useState ( timestampStartOfCurrentMonth ) ;
42
39
const [ endDateOfBillMonth , setEndDateOfBillMonth ] = useState ( Date . now ( ) ) ;
40
+ const [ totalCreditsUsed , setTotalCreditsUsed ] = useState < number > ( 0 ) ;
43
41
const [ isLoading , setIsLoading ] = useState < boolean > ( true ) ;
44
- const [ isStartedTimeDescending , setIsStartedTimeDescending ] = useState < boolean > ( true ) ;
45
42
46
43
useEffect ( ( ) => {
47
44
if ( ! team ) {
@@ -57,30 +54,8 @@ function TeamUsage() {
57
54
if ( ! team ) {
58
55
return ;
59
56
}
60
- if ( billedUsage . length === 0 ) {
61
- setIsLoading ( true ) ;
62
- }
63
- ( async ( ) => {
64
- const attributionId = AttributionId . render ( { kind : "team" , teamId : team . id } ) ;
65
- const request : BillableSessionRequest = {
66
- attributionId,
67
- startedTimeOrder : isStartedTimeDescending ? SortOrder . Descending : SortOrder . Ascending ,
68
- from : startDateOfBillMonth ,
69
- to : endDateOfBillMonth ,
70
- } ;
71
- try {
72
- const { server } = getGitpodService ( ) ;
73
- const billedUsageResult = await server . listBilledUsage ( request ) ;
74
- setBilledUsage ( billedUsageResult ) ;
75
- } catch ( error ) {
76
- if ( error . code === ErrorCodes . PERMISSION_DENIED ) {
77
- setErrorMessage ( "Access to usage details is restricted to team owners." ) ;
78
- }
79
- } finally {
80
- setIsLoading ( false ) ;
81
- }
82
- } ) ( ) ;
83
- } , [ team , startDateOfBillMonth , endDateOfBillMonth , isStartedTimeDescending ] ) ;
57
+ loadPage ( 1 ) ;
58
+ } , [ team , startDateOfBillMonth , endDateOfBillMonth ] ) ;
84
59
85
60
useEffect ( ( ) => {
86
61
if ( ! teamBillingMode ) {
@@ -91,6 +66,37 @@ function TeamUsage() {
91
66
}
92
67
} , [ teamBillingMode ] ) ;
93
68
69
+ const loadPage = async ( page : number = 1 ) => {
70
+ if ( ! team ) {
71
+ return ;
72
+ }
73
+ if ( usagePage === undefined ) {
74
+ setIsLoading ( true ) ;
75
+ setTotalCreditsUsed ( 0 ) ;
76
+ }
77
+ const attributionId = AttributionId . render ( { kind : "team" , teamId : team . id } ) ;
78
+ const request : ListBilledUsageRequest = {
79
+ attributionId,
80
+ fromDate : startDateOfBillMonth ,
81
+ toDate : endDateOfBillMonth ,
82
+ perPage : 50 ,
83
+ page,
84
+ } ;
85
+ try {
86
+ const page = await getGitpodService ( ) . server . listBilledUsage ( request ) ;
87
+ setUsagePage ( page ) ;
88
+ setTotalCreditsUsed ( Math . ceil ( page . totalCreditsUsed ) ) ;
89
+ } catch ( error ) {
90
+ if ( error . code === ErrorCodes . PERMISSION_DENIED ) {
91
+ setErrorMessage ( "Access to usage details is restricted to team owners." ) ;
92
+ } else {
93
+ setErrorMessage ( `Error: ${ error ?. message } ` ) ;
94
+ }
95
+ } finally {
96
+ setIsLoading ( false ) ;
97
+ }
98
+ } ;
99
+
94
100
const getType = ( type : BillableWorkspaceType ) => {
95
101
if ( type === "regular" ) {
96
102
return "Workspace" ;
@@ -111,12 +117,6 @@ function TeamUsage() {
111
117
return inMinutes + " min" ;
112
118
} ;
113
119
114
- const calculateTotalUsage = ( ) => {
115
- let totalCredits = 0 ;
116
- billedUsage . forEach ( ( session ) => ( totalCredits += session . credits ) ) ;
117
- return totalCredits . toLocaleString ( undefined , { minimumFractionDigits : 2 , maximumFractionDigits : 2 } ) ;
118
- } ;
119
-
120
120
const handleMonthClick = ( start : any , end : any ) => {
121
121
setStartDateOfBillMonth ( start ) ;
122
122
setEndDateOfBillMonth ( end ) ;
@@ -155,10 +155,7 @@ function TeamUsage() {
155
155
return new Date ( time ) . toLocaleDateString ( undefined , options ) . replace ( "at " , "" ) ;
156
156
} ;
157
157
158
- const lastResultOnCurrentPage = currentPage * resultsPerPage ;
159
- const firstResultOnCurrentPage = lastResultOnCurrentPage - resultsPerPage ;
160
- const totalNumberOfPages = Math . ceil ( billedUsage . length / resultsPerPage ) ;
161
- const currentPaginatedResults = billedUsage . slice ( firstResultOnCurrentPage , lastResultOnCurrentPage ) ;
158
+ const currentPaginatedResults = usagePage ?. sessions ?? [ ] ;
162
159
163
160
return (
164
161
< >
@@ -181,16 +178,18 @@ function TeamUsage() {
181
178
< div className = "text-base text-gray-500 truncate" > Previous Months</ div >
182
179
{ getBillingHistory ( ) }
183
180
</ div >
184
- < div className = "flex flex-col truncate" >
185
- < div className = "text-base text-gray-500" > Total usage</ div >
186
- < div className = "flex text-lg text-gray-600 font-semibold" >
187
- < CreditsSvg className = "my-auto mr-1" />
188
- < span > { calculateTotalUsage ( ) } Credits</ span >
181
+ { ! isLoading && (
182
+ < div className = "flex flex-col truncate" >
183
+ < div className = "text-base text-gray-500" > Total usage</ div >
184
+ < div className = "flex text-lg text-gray-600 font-semibold" >
185
+ < CreditsSvg className = "my-auto mr-1" />
186
+ < span > { totalCreditsUsed } Credits</ span >
187
+ </ div >
189
188
</ div >
190
- </ div >
189
+ ) }
191
190
</ div >
192
191
</ div >
193
- { ! isLoading && billedUsage . length === 0 && ! errorMessage && (
192
+ { ! isLoading && usagePage === undefined && ! errorMessage && (
194
193
< div className = "flex flex-col w-full mb-8" >
195
194
< h3 className = "text-center text-gray-500 mt-8" > No sessions found.</ h3 >
196
195
< p className = "text-center text-gray-500 mt-1" >
@@ -215,7 +214,7 @@ function TeamUsage() {
215
214
< Spinner className = "m-2 h-5 w-5 animate-spin" />
216
215
</ div >
217
216
) }
218
- { billedUsage . length > 0 && ! isLoading && (
217
+ { ! isLoading && currentPaginatedResults . length > 0 && (
219
218
< div className = "flex flex-col w-full mb-8" >
220
219
< ItemsList className = "mt-2 text-gray-400 dark:text-gray-500" >
221
220
< Item
@@ -233,17 +232,7 @@ function TeamUsage() {
233
232
</ ItemField >
234
233
< ItemField className = "my-auto" />
235
234
< ItemField className = "col-span-3 my-auto cursor-pointer" >
236
- < span
237
- className = "flex my-auto"
238
- onClick = { ( ) => setIsStartedTimeDescending ( ! isStartedTimeDescending ) }
239
- >
240
- Timestamp
241
- < SortArrow
242
- className = { `ml-2 h-4 w-4 my-auto ${
243
- isStartedTimeDescending ? "" : " transform rotate-180"
244
- } `}
245
- />
246
- </ span >
235
+ < span > Timestamp</ span >
247
236
</ ItemField >
248
237
</ Item >
249
238
{ currentPaginatedResults &&
@@ -310,12 +299,11 @@ function TeamUsage() {
310
299
) ;
311
300
} ) }
312
301
</ ItemsList >
313
- { billedUsage . length > resultsPerPage && (
302
+ { usagePage && usagePage . totalPages > 1 && (
314
303
< Pagination
315
- totalResults = { billedUsage . length }
316
- currentPage = { currentPage }
317
- setCurrentPage = { setCurrentPage }
318
- totalNumberOfPages = { totalNumberOfPages }
304
+ currentPage = { usagePage . page }
305
+ setPage = { ( page ) => loadPage ( page ) }
306
+ totalNumberOfPages = { usagePage . totalPages }
319
307
/>
320
308
) }
321
309
</ div >
0 commit comments