@@ -11,6 +11,7 @@ import {
11
11
RunningWorkspacePrebuildStarting ,
12
12
ContextURL ,
13
13
DisposableCollection ,
14
+ Team ,
14
15
} from "@gitpod/gitpod-protocol" ;
15
16
import { ErrorCodes } from "@gitpod/gitpod-protocol/lib/messaging/error" ;
16
17
import Modal from "../components/Modal" ;
@@ -25,6 +26,8 @@ import PrebuildLogs from "../components/PrebuildLogs";
25
26
import CodeText from "../components/CodeText" ;
26
27
import FeedbackComponent from "../feedback-form/FeedbackComponent" ;
27
28
import { isGitpodIo } from "../utils" ;
29
+ import { AttributionId } from "@gitpod/gitpod-protocol/lib/attribution" ;
30
+ import { TeamsContext } from "../teams/teams-context" ;
28
31
29
32
export interface CreateWorkspaceProps {
30
33
contextUrl : string ;
@@ -185,6 +188,11 @@ export default class CreateWorkspace extends React.Component<CreateWorkspaceProp
185
188
phase = StartPhase . Stopped ;
186
189
statusMessage = < LimitReachedOutOfHours /> ;
187
190
break ;
191
+ case ErrorCodes . PAYMENT_OUT_OF_CREDITS :
192
+ error = undefined ; // to hide the error (otherwise rendered behind the modal)
193
+ phase = StartPhase . Stopped ;
194
+ statusMessage = < SpendingLimitReachedModal hints = { this . state ?. error ?. data } /> ;
195
+ break ;
188
196
default :
189
197
statusMessage = (
190
198
< p className = "text-base text-gitpod-red w-96" >
@@ -335,6 +343,44 @@ function LimitReachedOutOfHours() {
335
343
</ LimitReachedModal >
336
344
) ;
337
345
}
346
+ function SpendingLimitReachedModal ( p : { hints : any } ) {
347
+ const { teams } = useContext ( TeamsContext ) ;
348
+ // const [attributionId, setAttributionId] = useState<AttributionId | undefined>();
349
+ const [ attributedTeam , setAttributedTeam ] = useState < Team | undefined > ( ) ;
350
+
351
+ useEffect ( ( ) => {
352
+ const attributionId : AttributionId | undefined =
353
+ p . hints && p . hints . attributionId && AttributionId . parse ( p . hints . attributionId ) ;
354
+ if ( attributionId ) {
355
+ // setAttributionId(attributionId);
356
+ if ( attributionId . kind === "team" ) {
357
+ const team = teams ?. find ( ( t ) => t . id === attributionId . teamId ) ;
358
+ setAttributedTeam ( team ) ;
359
+ }
360
+ }
361
+ } , [ ] ) ;
362
+
363
+ return (
364
+ < Modal visible = { true } closeable = { false } onClose = { ( ) => { } } >
365
+ < h3 className = "flex" >
366
+ < span className = "flex-grow" > Spending Limit Reached</ span >
367
+ </ h3 >
368
+ < div className = "border-t border-b border-gray-200 dark:border-gray-800 mt-4 -mx-6 px-6 py-2" >
369
+ < p className = "mt-1 mb-2 text-base dark:text-gray-400" > Please increase the spending limit and retry.</ p >
370
+ </ div >
371
+ < div className = "flex justify-end mt-6 space-x-2" >
372
+ < a href = { gitpodHostUrl . with ( { pathname : "billing" } ) . toString ( ) } >
373
+ < button > Billing Settings</ button >
374
+ </ a >
375
+ { attributedTeam && (
376
+ < a href = { gitpodHostUrl . with ( { pathname : `t/${ attributedTeam ?. slug } /billing` } ) . toString ( ) } >
377
+ < button > Team Billing</ button >
378
+ </ a >
379
+ ) }
380
+ </ div >
381
+ </ Modal >
382
+ ) ;
383
+ }
338
384
339
385
function RepositoryNotFoundView ( p : { error : StartWorkspaceError } ) {
340
386
const [ statusMessage , setStatusMessage ] = useState < React . ReactNode > ( ) ;
0 commit comments