6
6
7
7
import { useContext , useEffect , useState } from "react" ;
8
8
import { Redirect , useLocation } from "react-router" ;
9
- import { PageWithSubMenu } from "../components/PageWithSubMenu" ;
10
9
import { getCurrentTeam , TeamsContext } from "./teams-context" ;
11
- import { getTeamSettingsMenu } from "./TeamSettings" ;
12
10
import { PaymentContext } from "../payment-context" ;
13
11
import { getGitpodService } from "../service/service" ;
14
12
import { BillableSession , BillableWorkspaceType } from "@gitpod/gitpod-protocol/lib/usage" ;
15
13
import { AttributionId } from "@gitpod/gitpod-protocol/lib/attribution" ;
16
14
import { Item , ItemField , ItemsList } from "../components/ItemsList" ;
17
15
import moment from "moment" ;
18
- import Property from "../admin/Property" ;
19
- import Arrow from "../components/Arrow" ;
16
+ import Pagination from "../components/Pagination" ;
17
+ import Header from "../components/Header" ;
18
+ import creditsSvg from "../images/credits.svg" ;
20
19
21
20
function TeamUsage ( ) {
22
21
const { teams } = useContext ( TeamsContext ) ;
23
- const { showPaymentUI , showUsageBasedUI } = useContext ( PaymentContext ) ;
22
+ const { showUsageBasedUI } = useContext ( PaymentContext ) ;
24
23
const location = useLocation ( ) ;
25
24
const team = getCurrentTeam ( location , teams ) ;
26
25
const [ billedUsage , setBilledUsage ] = useState < BillableSession [ ] > ( [ ] ) ;
26
+ const [ currentPage , setCurrentPage ] = useState ( 1 ) ;
27
+ const [ resultsPerPage ] = useState ( 10 ) ;
27
28
28
29
useEffect ( ( ) => {
29
30
if ( ! team ) {
@@ -47,77 +48,104 @@ function TeamUsage() {
47
48
return "Prebuild" ;
48
49
} ;
49
50
50
- const getHours = ( endTime : number | undefined , startTime : number ) => {
51
- if ( ! endTime ) return "" ;
51
+ const getMinutes = ( endTime : number , startTime : number ) => {
52
+ const lengthOfUsage = Math . floor ( endTime - startTime ) ;
53
+ const inMinutes = ( lengthOfUsage / ( 1000 * 60 ) ) . toFixed ( 1 ) ;
54
+ return inMinutes + " min" ;
55
+ } ;
52
56
53
- return ( ( endTime - startTime ) / ( 1000 * 60 * 60 ) ) . toFixed ( 1 ) + "hrs" ;
57
+ const calculateTotalUsage = ( ) => {
58
+ let totalCredits = 0 ;
59
+ billedUsage . forEach ( ( session ) => ( totalCredits += session . credits ) ) ;
60
+ return totalCredits ;
54
61
} ;
55
62
63
+ const lastResultOnCurrentPage = currentPage * resultsPerPage ;
64
+ const firstResultOnCurrentPage = lastResultOnCurrentPage - resultsPerPage ;
65
+ const numberOfPages = Math . ceil ( billedUsage . length / resultsPerPage ) ;
66
+ const currentPaginatedResults = billedUsage . slice ( firstResultOnCurrentPage , lastResultOnCurrentPage ) ;
67
+
56
68
return (
57
- < PageWithSubMenu
58
- subMenu = { getTeamSettingsMenu ( { team, showPaymentUI, showUsageBasedUI } ) }
59
- title = "Usage"
60
- subtitle = "Manage team usage."
61
- >
62
- < div className = "flex flex-col w-full" >
63
- < div className = "flex w-full mt-6 mb-6" >
64
- < Property name = "Last 30 days" > Jun 1 - June 30</ Property >
65
- < Property name = "Workspaces" > 4,200 Min</ Property >
66
- < Property name = "Prebuilds" > 12,334 Min</ Property >
67
- </ div >
68
- </ div >
69
- < ItemsList className = "mt-2 text-gray-500" >
70
- < Item header = { false } className = "grid grid-cols-6 bg-gray-100" >
71
- < ItemField className = "my-auto" >
72
- < span > Type</ span >
73
- </ ItemField >
74
- < ItemField className = "my-auto" >
75
- < span > Class</ span >
76
- </ ItemField >
77
- < ItemField className = "my-auto" >
78
- < span > Amount</ span >
79
- </ ItemField >
80
- < ItemField className = "my-auto" >
81
- < span > Credits</ span >
82
- </ ItemField >
83
- < ItemField className = "my-auto" />
84
- </ Item >
85
- { billedUsage . map ( ( usage ) => (
86
- < div
87
- key = { usage . instanceId }
88
- className = "flex p-3 grid grid-cols-6 justify-between transition ease-in-out rounded-xl focus:bg-gitpod-kumquat-light"
89
- >
90
- < div className = "my-auto" >
91
- < span className = { usage . workspaceType === "prebuild" ? "text-orange-400" : "text-green-500" } >
92
- { getType ( usage . workspaceType ) }
93
- </ span >
94
- </ div >
95
- < div className = "my-auto" >
96
- < span className = "text-gray-400" > { usage . workspaceClass } </ span >
97
- </ div >
98
- < div className = "my-auto" >
99
- < span className = "text-gray-700" >
100
- { getHours (
101
- usage . endTime ? new Date ( usage . endTime ) . getTime ( ) : undefined ,
102
- new Date ( usage . startTime ) . getTime ( ) ,
103
- ) }
104
- </ span >
105
- </ div >
106
- < div className = "my-auto" >
107
- < span className = "text-gray-700" > { usage . credits . toFixed ( 1 ) } </ span >
108
- </ div >
109
- < div className = "my-auto" >
110
- < span className = "text-gray-400" >
111
- { moment ( new Date ( usage . startTime ) . toDateString ( ) ) . fromNow ( ) }
112
- </ span >
113
- </ div >
114
- < div className = "pr-2" >
115
- < Arrow up = { false } />
69
+ < >
70
+ < Header title = "Usage" subtitle = "Manage team usage." />
71
+ < div className = "app-container" >
72
+ < div className = "flex space-x-16" >
73
+ < div className = "flex" >
74
+ < div className = "space-y-8 mt-6 mb-6" style = { { width : "max-content" } } >
75
+ < div className = "flex flex-col truncate" >
76
+ < div className = "text-base text-gray-500 truncate" > Period</ div >
77
+ < div className = "text-lg text-gray-600 font-semibold truncate" > June 2022</ div >
78
+ </ div >
79
+ < div className = "flex flex-col truncate" >
80
+ < div className = "text-base text-gray-500" > Monthly usage</ div >
81
+ < div className = "flex text-lg text-gray-600 font-semibold" >
82
+ < img className = "mr-1" src = { creditsSvg } alt = { "credits icon" } />
83
+ < span > { calculateTotalUsage ( ) } Total Credits</ span >
84
+ </ div >
85
+ </ div >
116
86
</ div >
117
87
</ div >
118
- ) ) }
119
- </ ItemsList >
120
- </ PageWithSubMenu >
88
+ < div className = "flex flex-col w-full mb-8" >
89
+ < h3 > All Usage</ h3 >
90
+ < span className = "text-gray-500 mb-5" > View usage details of all team members.</ span >
91
+ < ItemsList className = "mt-2 text-gray-500" >
92
+ < Item header = { false } className = "grid grid-cols-5 bg-gray-100 mb-5" >
93
+ < ItemField className = "my-auto" >
94
+ < span > Type</ span >
95
+ </ ItemField >
96
+ < ItemField className = "my-auto" >
97
+ < span > Class</ span >
98
+ </ ItemField >
99
+ < ItemField className = "my-auto" >
100
+ < span > Usage</ span >
101
+ </ ItemField >
102
+ < ItemField className = "flex my-auto space-x-1" >
103
+ < img src = { creditsSvg } alt = { "credits icon" } />
104
+ < span > Credits</ span >
105
+ </ ItemField >
106
+ < ItemField className = "my-auto" />
107
+ </ Item >
108
+ { currentPaginatedResults . map ( ( usage ) => (
109
+ < div
110
+ key = { usage . instanceId }
111
+ className = "flex p-3 grid grid-cols-5 justify-between transition ease-in-out rounded-xl focus:bg-gitpod-kumquat-light"
112
+ >
113
+ < div className = "my-auto" >
114
+ < span > { getType ( usage . workspaceType ) } </ span >
115
+ </ div >
116
+ < div className = "my-auto" >
117
+ < span className = "text-gray-400" > { usage . workspaceClass } </ span >
118
+ </ div >
119
+ < div className = "my-auto" >
120
+ < span className = "text-gray-700" >
121
+ { getMinutes (
122
+ new Date ( usage . endTime ) . getTime ( ) ,
123
+ new Date ( usage . startTime ) . getTime ( ) ,
124
+ ) }
125
+ </ span >
126
+ </ div >
127
+ < div className = "my-auto" >
128
+ < span className = "text-gray-700" > { usage . credits . toFixed ( 1 ) } </ span >
129
+ </ div >
130
+ < div className = "my-auto" >
131
+ < span className = "text-gray-400" >
132
+ { moment ( new Date ( usage . startTime ) . toDateString ( ) ) . fromNow ( ) }
133
+ </ span >
134
+ </ div >
135
+ </ div >
136
+ ) ) }
137
+ </ ItemsList >
138
+ { billedUsage . length > resultsPerPage && (
139
+ < Pagination
140
+ currentPage = { currentPage }
141
+ setCurrentPage = { setCurrentPage }
142
+ numberOfPages = { numberOfPages }
143
+ />
144
+ ) }
145
+ </ div >
146
+ </ div >
147
+ </ div >
148
+ </ >
121
149
) ;
122
150
}
123
151
0 commit comments