@@ -9,9 +9,9 @@ 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
- BillableSession ,
13
12
BillableSessionRequest ,
14
13
BillableWorkspaceType ,
14
+ ExtendedBillableSession ,
15
15
SortOrder ,
16
16
} from "@gitpod/gitpod-protocol/lib/usage" ;
17
17
import { AttributionId } from "@gitpod/gitpod-protocol/lib/attribution" ;
@@ -22,14 +22,16 @@ 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
24
import { ReactComponent as SortArrow } from "../images/sort-arrow.svg" ;
25
+ import { ReactComponent as UsageIcon } from "../images/usage-default.svg" ;
25
26
import { BillingMode } from "@gitpod/gitpod-protocol/lib/billing-mode" ;
27
+ import { toRemoteURL } from "../projects/render-utils" ;
26
28
27
29
function TeamUsage ( ) {
28
30
const { teams } = useContext ( TeamsContext ) ;
29
31
const location = useLocation ( ) ;
30
32
const team = getCurrentTeam ( location , teams ) ;
31
33
const [ teamBillingMode , setTeamBillingMode ] = useState < BillingMode | undefined > ( undefined ) ;
32
- const [ billedUsage , setBilledUsage ] = useState < BillableSession [ ] > ( [ ] ) ;
34
+ const [ billedUsage , setBilledUsage ] = useState < ExtendedBillableSession [ ] > ( [ ] ) ;
33
35
const [ currentPage , setCurrentPage ] = useState ( 1 ) ;
34
36
const [ resultsPerPage ] = useState ( 50 ) ;
35
37
const [ errorMessage , setErrorMessage ] = useState ( "" ) ;
@@ -55,6 +57,9 @@ function TeamUsage() {
55
57
if ( ! team ) {
56
58
return ;
57
59
}
60
+ if ( billedUsage . length === 0 ) {
61
+ setIsLoading ( true ) ;
62
+ }
58
63
( async ( ) => {
59
64
const attributionId = AttributionId . render ( { kind : "team" , teamId : team . id } ) ;
60
65
const request : BillableSessionRequest = {
@@ -64,7 +69,8 @@ function TeamUsage() {
64
69
to : endDateOfBillMonth ,
65
70
} ;
66
71
try {
67
- const billedUsageResult = await getGitpodService ( ) . server . listBilledUsage ( request ) ;
72
+ const { server } = getGitpodService ( ) ;
73
+ const billedUsageResult = await server . listBilledUsage ( request ) ;
68
74
setBilledUsage ( billedUsageResult ) ;
69
75
} catch ( error ) {
70
76
if ( error . code === ErrorCodes . PERMISSION_DENIED ) {
@@ -92,7 +98,7 @@ function TeamUsage() {
92
98
return "Prebuild" ;
93
99
} ;
94
100
95
- const getMinutes = ( usage : BillableSession ) => {
101
+ const getMinutes = ( usage : ExtendedBillableSession ) => {
96
102
let end ;
97
103
if ( ! usage . endTime ) {
98
104
end = new Date ( Date . now ( ) ) . getTime ( ) ;
@@ -141,7 +147,7 @@ function TeamUsage() {
141
147
const displayTime = ( time : string ) => {
142
148
const options : Intl . DateTimeFormatOptions = {
143
149
day : "numeric" ,
144
- month : "long " ,
150
+ month : "short " ,
145
151
year : "numeric" ,
146
152
hour : "numeric" ,
147
153
minute : "numeric" ,
@@ -184,7 +190,7 @@ function TeamUsage() {
184
190
</ div >
185
191
</ div >
186
192
</ div >
187
- { billedUsage . length === 0 && ! errorMessage && ! isLoading && (
193
+ { ! isLoading && billedUsage . length === 0 && ! errorMessage && (
188
194
< div className = "flex flex-col w-full mb-8" >
189
195
< h3 className = "text-center text-gray-500 mt-8" > No sessions found.</ h3 >
190
196
< p className = "text-center text-gray-500 mt-1" >
@@ -212,26 +218,23 @@ function TeamUsage() {
212
218
{ billedUsage . length > 0 && ! isLoading && (
213
219
< div className = "flex flex-col w-full mb-8" >
214
220
< ItemsList className = "mt-2 text-gray-500" >
215
- < Item header = { false } className = "grid grid-cols-5 bg-gray-100 mb-5" >
216
- < ItemField className = "my-auto" >
221
+ < Item header = { false } className = "grid grid-cols-12 gap-x-3 bg-gray-100 mb-5" >
222
+ < ItemField className = "col-span-2 my-auto" >
217
223
< span > Type</ span >
218
224
</ ItemField >
219
- < ItemField className = "my-auto" >
220
- < span > Class </ span >
225
+ < ItemField className = "col-span-5 my-auto" >
226
+ < span > ID </ span >
221
227
</ ItemField >
222
228
< ItemField className = "my-auto" >
223
- < span > Usage</ span >
224
- </ ItemField >
225
- < ItemField className = "flex my-auto" >
226
- < CreditsSvg className = "my-auto mr-1" />
227
229
< span > Credits</ span >
228
230
</ ItemField >
229
- < ItemField className = "my-auto cursor-pointer" >
231
+ < ItemField className = "my-auto" />
232
+ < ItemField className = "col-span-3 my-auto cursor-pointer" >
230
233
< span
231
234
className = "flex my-auto"
232
235
onClick = { ( ) => setIsStartedTimeDescending ( ! isStartedTimeDescending ) }
233
236
>
234
- Started
237
+ Timestamp
235
238
< SortArrow
236
239
className = { `h-4 w-4 my-auto ${
237
240
isStartedTimeDescending ? "" : " transform rotate-180"
@@ -241,30 +244,66 @@ function TeamUsage() {
241
244
</ ItemField >
242
245
</ Item >
243
246
{ currentPaginatedResults &&
244
- currentPaginatedResults . map ( ( usage ) => (
245
- < div
246
- key = { usage . instanceId }
247
- className = "flex p-3 grid grid-cols-5 justify-between transition ease-in-out rounded-xl focus:bg-gitpod-kumquat-light"
248
- >
249
- < div className = "my-auto" >
250
- < span > { getType ( usage . workspaceType ) } </ span >
251
- </ div >
252
- < div className = "my-auto" >
253
- < span className = "text-gray-400" > { usage . workspaceClass } </ span >
254
- </ div >
255
- < div className = "my-auto" >
256
- < span className = "text-gray-700" > { getMinutes ( usage ) } </ span >
257
- </ div >
258
- < div className = "my-auto" >
259
- < span className = "text-gray-700" > { usage . credits . toFixed ( 1 ) } </ span >
260
- </ div >
261
- < div className = "my-auto" >
262
- < span className = "text-gray-400" >
263
- { displayTime ( usage . startTime ) }
264
- </ span >
247
+ currentPaginatedResults . map ( ( usage ) => {
248
+ return (
249
+ < div
250
+ key = { usage . instanceId }
251
+ className = "flex p-3 grid grid-cols-12 gap-x-3 justify-between transition ease-in-out rounded-xl focus:bg-gitpod-kumquat-light"
252
+ >
253
+ < div className = "flex flex-col col-span-2 my-auto" >
254
+ < span className = "text-gray-700 dark:text-gray-400" >
255
+ { getType ( usage . workspaceType ) }
256
+ </ span >
257
+ < span className = "text-sm text-gray-400 dark:text-gray-600" >
258
+ { usage . workspaceClass }
259
+ </ span >
260
+ </ div >
261
+ < div className = "flex flex-col col-span-5 my-auto" >
262
+ < span className = "truncate text-gray-700 dark:text-gray-400" >
263
+ { usage . workspaceId }
264
+ </ span >
265
+ < span className = "text-sm truncate text-gray-400 dark:text-gray-600" >
266
+ { usage . contextURL && toRemoteURL ( usage . contextURL ) }
267
+ </ span >
268
+ </ div >
269
+ < div className = "flex flex-col my-auto" >
270
+ < span className = "text-right text-gray-700 dark:text-gray-400" >
271
+ { usage . credits . toFixed ( 1 ) }
272
+ </ span >
273
+ < span className = "text-right truncate text-sm text-gray-400 dark:text-gray-600" >
274
+ { getMinutes ( usage ) }
275
+ </ span >
276
+ </ div >
277
+ < div className = "my-auto" />
278
+ < div className = "flex flex-col col-span-3 my-auto" >
279
+ < span className = "text-gray-400 truncate" >
280
+ { displayTime ( usage . startTime ) }
281
+ </ span >
282
+ < div className = "flex" >
283
+ { usage . workspaceType === "prebuild" ? (
284
+ < UsageIcon className = "my-auto" />
285
+ ) : (
286
+ ""
287
+ ) }
288
+ { usage . workspaceType === "prebuild" ? (
289
+ < span className = "text-sm text-gray-400" > Gitpod</ span >
290
+ ) : (
291
+ < div className = "flex" >
292
+ < img
293
+ className = "my-auto rounded-full w-4 h-4 inline-block align-text-bottom mr-2 overflow-hidden"
294
+ src = { usage . user ?. avatarUrl || "" }
295
+ alt = "user avatar"
296
+ />
297
+ < span className = "text-sm text-gray-400" >
298
+ { usage . user ?. name }
299
+ </ span >
300
+ </ div >
301
+ ) }
302
+ </ div >
303
+ </ div >
265
304
</ div >
266
- </ div >
267
- ) ) }
305
+ ) ;
306
+ } ) }
268
307
</ ItemsList >
269
308
{ billedUsage . length > resultsPerPage && (
270
309
< Pagination
0 commit comments