@@ -15,6 +15,7 @@ import { Item, ItemField, ItemsList } from "../components/ItemsList";
15
15
import moment from "moment" ;
16
16
import Pagination from "../components/Pagination" ;
17
17
import Header from "../components/Header" ;
18
+ import { ErrorCodes } from "@gitpod/gitpod-protocol/lib/messaging/error" ;
18
19
19
20
function TeamUsage ( ) {
20
21
const { teams } = useContext ( TeamsContext ) ;
@@ -24,15 +25,22 @@ function TeamUsage() {
24
25
const [ billedUsage , setBilledUsage ] = useState < BillableSession [ ] > ( [ ] ) ;
25
26
const [ currentPage , setCurrentPage ] = useState ( 1 ) ;
26
27
const [ resultsPerPage ] = useState ( 10 ) ;
28
+ const [ errorMessage , setErrorMessage ] = useState ( "" ) ;
27
29
28
30
useEffect ( ( ) => {
29
31
if ( ! team ) {
30
32
return ;
31
33
}
32
34
( async ( ) => {
33
35
const attributionId = AttributionId . render ( { kind : "team" , teamId : team . id } ) ;
34
- const billedUsageResult = await getGitpodService ( ) . server . listBilledUsage ( attributionId ) ;
35
- setBilledUsage ( billedUsageResult ) ;
36
+ try {
37
+ const billedUsageResult = await getGitpodService ( ) . server . listBilledUsage ( attributionId ) ;
38
+ setBilledUsage ( billedUsageResult ) ;
39
+ } catch ( error ) {
40
+ if ( error . code === ErrorCodes . PERMISSION_DENIED ) {
41
+ setErrorMessage ( "Please request access to your administrator." ) ;
42
+ }
43
+ }
36
44
} ) ( ) ;
37
45
} , [ team ] ) ;
38
46
@@ -75,77 +83,18 @@ function TeamUsage() {
75
83
< >
76
84
< Header title = "Usage" subtitle = "Manage team usage." />
77
85
< div className = "app-container pt-9" >
78
- < div className = "flex space-x-16" >
79
- < div className = "flex" >
80
- < div className = "space-y-8 mb-6" style = { { width : "max-content" } } >
81
- < div className = "flex flex-col truncate" >
82
- < div className = "text-base text-gray-500 truncate" > Period</ div >
83
- < div className = "text-lg text-gray-600 font-semibold truncate" > June 2022</ div >
84
- </ div >
85
- < div className = "flex flex-col truncate" >
86
- < div className = "text-base text-gray-500" > Total usage</ div >
87
- < div className = "flex text-lg text-gray-600 font-semibold" >
88
- < svg
89
- className = "my-auto mr-1"
90
- width = "20"
91
- height = "20"
92
- fill = "none"
93
- xmlns = "http://www.w3.org/2000/svg"
94
- >
95
- < path
96
- fill-rule = "evenodd"
97
- clip-rule = "evenodd"
98
- d = "M5 2a3 3 0 0 0-3 3v10a3 3 0 0 0 3 3h10a3 3 0 0 0 3-3V5a3 3 0 0 0-3-3H5Zm5.2 11.4a3.2 3.2 0 1 0 0-6.4 3.2 3.2 0 0 0 0 6.4Z"
99
- fill = "url(#a)"
100
- />
101
- < defs >
102
- < linearGradient
103
- id = "a"
104
- x1 = "4.3"
105
- y1 = "4.3"
106
- x2 = "16.071"
107
- y2 = "17.107"
108
- gradientUnits = "userSpaceOnUse"
109
- >
110
- < stop stop-color = "#FFAD33" />
111
- < stop offset = "1" stop-color = "#FF8A00" />
112
- </ linearGradient >
113
- </ defs >
114
- </ svg >
115
- < span > { calculateTotalUsage ( ) } Total Credits</ span >
86
+ { errorMessage && < h3 > { errorMessage } </ h3 > }
87
+ { ! errorMessage && (
88
+ < div className = "flex space-x-16" >
89
+ < div className = "flex" >
90
+ < div className = "space-y-8 mb-6" style = { { width : "max-content" } } >
91
+ < div className = "flex flex-col truncate" >
92
+ < div className = "text-base text-gray-500 truncate" > Period</ div >
93
+ < div className = "text-lg text-gray-600 font-semibold truncate" > June 2022</ div >
116
94
</ div >
117
- </ div >
118
- </ div >
119
- </ div >
120
- { billedUsage . length === 0 && (
121
- < div className = "flex flex-col w-full mb-8" >
122
- < h3 className = "text-center text-gray-500 mt-8" > No sessions found.</ h3 >
123
- < p className = "text-center text-gray-500 mt-1" >
124
- Have you started any
125
- < a className = "gp-link" href = { gitpodHostUrl . asWorkspacePage ( ) . toString ( ) } >
126
- { " " }
127
- workspaces
128
- </ a > { " " }
129
- or checked your other teams?
130
- </ p >
131
- </ div >
132
- ) }
133
- { billedUsage . length > 0 && (
134
- < div className = "flex flex-col w-full mb-8" >
135
- < h3 > All Usage</ h3 >
136
- < span className = "text-gray-500 mb-5" > View usage details of all team members.</ span >
137
- < ItemsList className = "mt-2 text-gray-500" >
138
- < Item header = { false } className = "grid grid-cols-5 bg-gray-100 mb-5" >
139
- < ItemField className = "my-auto" >
140
- < span > Type</ span >
141
- </ ItemField >
142
- < ItemField className = "my-auto" >
143
- < span > Class</ span >
144
- </ ItemField >
145
- < ItemField className = "my-auto" >
146
- < span > Usage</ span >
147
- </ ItemField >
148
- < ItemField className = "flex my-auto" >
95
+ < div className = "flex flex-col truncate" >
96
+ < div className = "text-base text-gray-500" > Total usage</ div >
97
+ < div className = "flex text-lg text-gray-600 font-semibold" >
149
98
< svg
150
99
className = "my-auto mr-1"
151
100
width = "20"
@@ -173,46 +122,108 @@ function TeamUsage() {
173
122
</ linearGradient >
174
123
</ defs >
175
124
</ svg >
176
- < span > Credits</ span >
177
- </ ItemField >
178
- < ItemField className = "my-auto" />
179
- </ Item >
180
- { currentPaginatedResults &&
181
- currentPaginatedResults . map ( ( usage ) => (
182
- < div
183
- key = { usage . instanceId }
184
- className = "flex p-3 grid grid-cols-5 justify-between transition ease-in-out rounded-xl focus:bg-gitpod-kumquat-light"
185
- >
186
- < div className = "my-auto" >
187
- < span > { getType ( usage . workspaceType ) } </ span >
188
- </ div >
189
- < div className = "my-auto" >
190
- < span className = "text-gray-400" > { usage . workspaceClass } </ span >
191
- </ div >
192
- < div className = "my-auto" >
193
- < span className = "text-gray-700" > { getMinutes ( usage ) } </ span >
194
- </ div >
195
- < div className = "my-auto" >
196
- < span className = "text-gray-700" > { usage . credits . toFixed ( 1 ) } </ span >
197
- </ div >
198
- < div className = "my-auto" >
199
- < span className = "text-gray-400" >
200
- { moment ( new Date ( usage . startTime ) . toDateString ( ) ) . fromNow ( ) }
201
- </ span >
202
- </ div >
203
- </ div >
204
- ) ) }
205
- </ ItemsList >
206
- { billedUsage . length > resultsPerPage && (
207
- < Pagination
208
- currentPage = { currentPage }
209
- setCurrentPage = { setCurrentPage }
210
- numberOfPages = { numberOfPages }
211
- />
212
- ) }
125
+ < span > { calculateTotalUsage ( ) } Total Credits</ span >
126
+ </ div >
127
+ </ div >
128
+ </ div >
213
129
</ div >
214
- ) }
215
- </ div >
130
+ { billedUsage . length === 0 && ! errorMessage && (
131
+ < div className = "flex flex-col w-full mb-8" >
132
+ < h3 className = "text-center text-gray-500 mt-8" > No sessions found.</ h3 >
133
+ < p className = "text-center text-gray-500 mt-1" >
134
+ Have you started any
135
+ < a className = "gp-link" href = { gitpodHostUrl . asWorkspacePage ( ) . toString ( ) } >
136
+ { " " }
137
+ workspaces
138
+ </ a > { " " }
139
+ or checked your other teams?
140
+ </ p >
141
+ </ div >
142
+ ) }
143
+ { billedUsage . length > 0 && (
144
+ < div className = "flex flex-col w-full mb-8" >
145
+ < h3 > All Usage</ h3 >
146
+ < span className = "text-gray-500 mb-5" > View usage details of all team members.</ span >
147
+ < ItemsList className = "mt-2 text-gray-500" >
148
+ < Item header = { false } className = "grid grid-cols-5 bg-gray-100 mb-5" >
149
+ < ItemField className = "my-auto" >
150
+ < span > Type</ span >
151
+ </ ItemField >
152
+ < ItemField className = "my-auto" >
153
+ < span > Class</ span >
154
+ </ ItemField >
155
+ < ItemField className = "my-auto" >
156
+ < span > Usage</ span >
157
+ </ ItemField >
158
+ < ItemField className = "flex my-auto" >
159
+ < svg
160
+ className = "my-auto mr-1"
161
+ width = "20"
162
+ height = "20"
163
+ fill = "none"
164
+ xmlns = "http://www.w3.org/2000/svg"
165
+ >
166
+ < path
167
+ fill-rule = "evenodd"
168
+ clip-rule = "evenodd"
169
+ d = "M5 2a3 3 0 0 0-3 3v10a3 3 0 0 0 3 3h10a3 3 0 0 0 3-3V5a3 3 0 0 0-3-3H5Zm5.2 11.4a3.2 3.2 0 1 0 0-6.4 3.2 3.2 0 0 0 0 6.4Z"
170
+ fill = "url(#a)"
171
+ />
172
+ < defs >
173
+ < linearGradient
174
+ id = "a"
175
+ x1 = "4.3"
176
+ y1 = "4.3"
177
+ x2 = "16.071"
178
+ y2 = "17.107"
179
+ gradientUnits = "userSpaceOnUse"
180
+ >
181
+ < stop stop-color = "#FFAD33" />
182
+ < stop offset = "1" stop-color = "#FF8A00" />
183
+ </ linearGradient >
184
+ </ defs >
185
+ </ svg >
186
+ < span > Credits</ span >
187
+ </ ItemField >
188
+ < ItemField className = "my-auto" />
189
+ </ Item >
190
+ { currentPaginatedResults &&
191
+ currentPaginatedResults . map ( ( usage ) => (
192
+ < div
193
+ key = { usage . instanceId }
194
+ className = "flex p-3 grid grid-cols-5 justify-between transition ease-in-out rounded-xl focus:bg-gitpod-kumquat-light"
195
+ >
196
+ < div className = "my-auto" >
197
+ < span > { getType ( usage . workspaceType ) } </ span >
198
+ </ div >
199
+ < div className = "my-auto" >
200
+ < span className = "text-gray-400" > { usage . workspaceClass } </ span >
201
+ </ div >
202
+ < div className = "my-auto" >
203
+ < span className = "text-gray-700" > { getMinutes ( usage ) } </ span >
204
+ </ div >
205
+ < div className = "my-auto" >
206
+ < span className = "text-gray-700" > { usage . credits . toFixed ( 1 ) } </ span >
207
+ </ div >
208
+ < div className = "my-auto" >
209
+ < span className = "text-gray-400" >
210
+ { moment ( new Date ( usage . startTime ) . toDateString ( ) ) . fromNow ( ) }
211
+ </ span >
212
+ </ div >
213
+ </ div >
214
+ ) ) }
215
+ </ ItemsList >
216
+ { billedUsage . length > resultsPerPage && (
217
+ < Pagination
218
+ currentPage = { currentPage }
219
+ setCurrentPage = { setCurrentPage }
220
+ numberOfPages = { numberOfPages }
221
+ />
222
+ ) }
223
+ </ div >
224
+ ) }
225
+ </ div >
226
+ ) }
216
227
</ div >
217
228
</ >
218
229
) ;
0 commit comments