66
77import { useContext , useEffect , useState } from "react" ;
88import { Redirect , useLocation } from "react-router" ;
9- import { PageWithSubMenu } from "../components/PageWithSubMenu" ;
109import { getCurrentTeam , TeamsContext } from "./teams-context" ;
11- import { getTeamSettingsMenu } from "./TeamSettings" ;
1210import { PaymentContext } from "../payment-context" ;
1311import { getGitpodService } from "../service/service" ;
1412import { BillableSession , BillableWorkspaceType } from "@gitpod/gitpod-protocol/lib/usage" ;
1513import { AttributionId } from "@gitpod/gitpod-protocol/lib/attribution" ;
1614import { Item , ItemField , ItemsList } from "../components/ItemsList" ;
1715import 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" ;
2019
2120function TeamUsage ( ) {
2221 const { teams } = useContext ( TeamsContext ) ;
23- const { showPaymentUI , showUsageBasedUI } = useContext ( PaymentContext ) ;
22+ const { showUsageBasedUI } = useContext ( PaymentContext ) ;
2423 const location = useLocation ( ) ;
2524 const team = getCurrentTeam ( location , teams ) ;
2625 const [ billedUsage , setBilledUsage ] = useState < BillableSession [ ] > ( [ ] ) ;
26+ const [ currentPage , setCurrentPage ] = useState ( 1 ) ;
27+ const [ resultsPerPage ] = useState ( 10 ) ;
2728
2829 useEffect ( ( ) => {
2930 if ( ! team ) {
@@ -47,77 +48,104 @@ function TeamUsage() {
4748 return "Prebuild" ;
4849 } ;
4950
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+ } ;
5256
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 ;
5461 } ;
5562
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+
5668 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 >
11686 </ div >
11787 </ 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+ </ >
121149 ) ;
122150}
123151
0 commit comments