@@ -13,6 +13,9 @@ import { getGitpodService } from "../service/service";
13
13
14
14
import { ReactComponent as Alert } from "../images/exclamation.svg" ;
15
15
import { ReactComponent as Success } from "../images/check-circle.svg" ;
16
+ import { LicenseInfo } from "@gitpod/gitpod-protocol" ;
17
+ import { ReactComponent as XSvg } from "../images/x.svg" ;
18
+ import { ReactComponent as CheckSvg } from "../images/check.svg" ;
16
19
17
20
export default function License ( ) {
18
21
const { license, setLicense } = useContext ( LicenseContext ) ;
@@ -33,12 +36,7 @@ export default function License() {
33
36
// if user seats is 0, it means that there is user limit in the license
34
37
const userLimit = license ?. seats == 0 ? "Unlimited" : license ?. seats ;
35
38
36
- const [ licenseLevel , paid , msg , tick ] = getSubscriptionLevel (
37
- license ?. plan || "" ,
38
- license ?. userCount || 0 ,
39
- license ?. seats || 0 ,
40
- license ?. fallbackAllowed || false ,
41
- ) ;
39
+ const [ licenseLevel , paid , statusMessage ] = license ? getSubscriptionLevel ( license ) : defaultMessage ( ) ;
42
40
43
41
return (
44
42
< div >
@@ -49,40 +47,41 @@ export default function License() {
49
47
>
50
48
< div className = "flex flex-row space-x-4" >
51
49
< Card className = "bg-gray-800 dark:bg-gray-100 text-gray-300 dark:text-gray-400" >
52
- < p className = "text-white dark:text-black font-bold pt-4" > { licenseLevel } </ p >
53
- < p className = "dark:text-gray-500" > { paid } </ p >
54
- < div className = "pt-4" > Available features:</ div >
55
- { features &&
56
- features . map ( ( feat : string ) => (
57
- < div className = "flex" >
58
- { featureList ?. includes ( feat ) ? (
59
- < span className = "pr-1" > ✓</ span >
60
- ) : (
61
- < span className = "pr-1" > ✗</ span >
62
- ) }
63
- { capitalizeInitials ( feat ) }
64
- </ div >
65
- ) ) }
50
+ { licenseLevel }
51
+ { paid }
52
+ < div className = "pt-4 font-semibold" > Available features:</ div >
53
+ < div className = "flex flex-col pt-1" >
54
+ { features &&
55
+ features . map ( ( feat : string ) => (
56
+ < span className = "inline-flex px-1" >
57
+ { featureList ?. includes ( feat ) ? (
58
+ < CheckSvg className = "w-5" strokeWidth = "1" />
59
+ ) : (
60
+ < XSvg strokeWidth = "1" className = "w-5" />
61
+ ) }
62
+ < span > { capitalizeInitials ( feat ) } </ span >
63
+ </ span >
64
+ ) ) }
65
+ </ div >
66
66
</ Card >
67
- < Card className = "bg-gray-100 dark:bg-gray-900 text-gray-600 dark:text-gray-600 relative" >
68
- < div className = "text-gray-600 dark:text-gray-200 py-4 flex-row flex items-center" >
69
- < div > { msg } </ div >
70
- < div className = "px-4" > { getLicenseValidIcon ( tick ) } </ div >
67
+ < Card className = "bg-gray-100 dark:bg-gray-900 text-gray-600 dark:text-gray-600" >
68
+ < div className = "text-gray-600 dark:text-gray-200 py-4 flex-row flex font-semibold items-center" >
69
+ { statusMessage }
71
70
</ div >
72
- < p className = "dark:text-gray-500" > Registered Users</ p >
71
+ < p className = "dark:text-gray-500 font-semibold " > Registered Users</ p >
73
72
< span className = "dark:text-gray-300 pt-1 text-lg" > { license ?. userCount || 0 } </ span >
74
73
< span className = "dark:text-gray-500 text-gray-400 pt-1 text-lg" > / { userLimit } </ span >
75
- < p className = "dark:text-gray-500 pt-2" > License Type</ p >
74
+ < p className = "dark:text-gray-500 pt-2 font-semibold " > License Type</ p >
76
75
< h4 className = "dark:text-gray-300 pt-1 text-lg" > { capitalizeInitials ( license ?. type || "" ) } </ h4 >
77
- < div className = "flex justify-end absolute bottom-4 right-4 " >
76
+ < div className = "flex justify-end bottom-2 relative " >
78
77
< button
79
78
type = "button"
80
79
onClick = { ( e ) => {
81
80
e . preventDefault ( ) ;
82
81
window . location . href = "https://www.gitpod.io/self-hosted" ;
83
82
} }
84
83
>
85
- Compare Plans
84
+ < div className = "font-semibold" > Compare Plans</ div >
86
85
</ button >
87
86
</ div >
88
87
</ Card >
@@ -101,66 +100,112 @@ function capitalizeInitials(str: string): string {
101
100
. join ( " " ) ;
102
101
}
103
102
104
- function getSubscriptionLevel ( level : string , userCount : number , seats : number , fallbackAllowed : boolean ) : string [ ] {
105
- switch ( level ) {
106
- case "prod" : {
107
- return professionalPlan ( userCount , seats ) ;
108
- }
109
- case "community" : {
110
- return communityPlan ( userCount , seats , fallbackAllowed ) ;
111
- }
112
- case "trial" : {
113
- return [ "Trial" , "Free" , "You have a trial license." , "grey-tick" ] ;
114
- }
103
+ function getSubscriptionLevel ( license : LicenseInfo ) : ReactElement [ ] {
104
+ switch ( license . plan ) {
105
+ case "prod" :
106
+ case "trial" :
107
+ return professionalPlan ( license . userCount || 0 , license . seats , license . plan == "trial" , license . validUntil ) ;
108
+ case "community" :
109
+ return communityPlan ( license . userCount || 0 , license . seats , license . fallbackAllowed ) ;
115
110
default : {
116
- return [ "Unknown" , "Free" , "No active licenses." , "red-cross" ] ;
111
+ return defaultMessage ( ) ;
117
112
}
118
113
}
119
114
}
120
115
121
- function professionalPlan ( userCount : number , seats : number ) : string [ ] {
122
- const aboveLimit : boolean = userCount > seats ;
123
- let msg : string , tick : string ;
124
- if ( aboveLimit ) {
125
- msg = "You have exceeded the usage limit." ;
126
- tick = "red-cross" ;
127
- } else {
128
- msg = "You have an active professional license." ;
129
- tick = "green-tick" ;
130
- }
116
+ function licenseLevel ( level : string ) : ReactElement {
117
+ return < p className = "text-white dark:text-black font-bold pt-4" > { level } </ p > ;
118
+ }
119
+
120
+ function additionalLicenseInfo ( data : string ) : ReactElement {
121
+ return < p className = "dark:text-gray-500" > { data } </ p > ;
122
+ }
123
+
124
+ function defaultMessage ( ) : ReactElement [ ] {
125
+ const alertMessage = ( ) => {
126
+ return (
127
+ < >
128
+ < div > Inactive or unknown license</ div >
129
+ < div className = "flex justify-right my-4 mx-1" >
130
+ < Alert fill = "grey" className = "h-8 w-8" />
131
+ </ div >
132
+ </ >
133
+ ) ;
134
+ } ;
131
135
132
- return [ "Professional" , "Paid" , msg , tick ] ;
136
+ return [ licenseLevel ( "Inactive" ) , additionalLicenseInfo ( "Free" ) , alertMessage ( ) ] ;
133
137
}
134
138
135
- function communityPlan ( userCount : number , seats : number , fallbackAllowed : boolean ) : string [ ] {
139
+ function professionalPlan ( userCount : number , seats : number , trial : boolean , validUntil : string ) : ReactElement [ ] {
140
+ const alertMessage = ( aboveLimit : boolean ) => {
141
+ return aboveLimit ? (
142
+ < >
143
+ < div className = "text-red-600" > You have exceeded the usage limit.</ div >
144
+ < div className = "flex justify-right my-4 mx-1" >
145
+ < Alert fill = "red" className = "h-6 w-6" />
146
+ </ div >
147
+ </ >
148
+ ) : (
149
+ < >
150
+ < div className = "text-green-600" > You have an active professional license.</ div >
151
+ < div className = "flex justify-right my-4 mx-1" >
152
+ < Success fill = "green" className = "h-8 w-8" />
153
+ </ div >
154
+ </ >
155
+ ) ;
156
+ } ;
157
+
136
158
const aboveLimit : boolean = userCount > seats ;
137
159
138
- let msg : string = "You are using the free community edition" ;
139
- let tick : string = "green-tick" ;
140
- if ( aboveLimit ) {
141
- if ( fallbackAllowed ) {
142
- msg = "No active license. You are using the community edition." ;
143
- tick = "grey-tick" ;
160
+ const licenseTitle = ( ) => {
161
+ if ( trial ) {
162
+ const expDate = new Date ( validUntil ) ;
163
+ if ( typeof expDate . getTime !== "function" ) {
164
+ return additionalLicenseInfo ( "Trial" ) ;
165
+ } else {
166
+ return additionalLicenseInfo ( "Trial expires on " + expDate . toLocaleDateString ( ) ) ;
167
+ }
144
168
} else {
145
- msg = "No active license. You have exceeded the usage limit." ;
146
- tick = "red-cross" ;
169
+ return additionalLicenseInfo ( "Paid" ) ;
147
170
}
148
- }
171
+ } ;
149
172
150
- return [ "Community" , "Free" , msg , tick ] ;
173
+ return [ licenseLevel ( "Professional" ) , licenseTitle ( ) , alertMessage ( aboveLimit ) ] ;
151
174
}
152
175
153
- function getLicenseValidIcon ( iconname : string ) : ReactElement {
154
- switch ( iconname ) {
155
- case "green-tick" :
156
- return < Success fill = "green" className = "h-8 w-8" /> ;
157
- case "grey-tick" :
158
- return < Success fill = "gray" className = "h-8 w-8" /> ;
159
- case "red-cross" :
160
- return < Alert fill = "red" className = "h-8 w-8" /> ;
161
- default :
162
- return < Alert fill = "gray" className = "h-8 w-8" /> ;
163
- }
176
+ function communityPlan ( userCount : number , seats : number , fallbackAllowed : boolean ) : ReactElement [ ] {
177
+ const alertMessage = ( aboveLimit : boolean ) => {
178
+ if ( aboveLimit ) {
179
+ return fallbackAllowed ? (
180
+ < >
181
+ < div > No active license. You are using community edition.</ div >
182
+ < div className = "flex justify-right my-4 mx-1" >
183
+ < Success fill = "grey" className = "h-8 w-8" />
184
+ </ div >
185
+ </ >
186
+ ) : (
187
+ < >
188
+ < div className = "text-red-600" > No active license. You have exceeded the usage limit.</ div >
189
+ < div className = "flex justify-right my-4 mx-1" >
190
+ < Alert fill = "red" className = "h-8 w-8" />
191
+ </ div >
192
+ </ >
193
+ ) ;
194
+ } else {
195
+ return (
196
+ < >
197
+ < div > You are using the free community edition.</ div >
198
+ < div className = "flex justify-right my-4 mx-1" >
199
+ < Success fill = "green" className = "h-8 w-8" />
200
+ </ div >
201
+ </ >
202
+ ) ;
203
+ }
204
+ } ;
205
+
206
+ const aboveLimit : boolean = userCount > seats ;
207
+
208
+ return [ licenseLevel ( "Community" ) , additionalLicenseInfo ( "Free" ) , alertMessage ( aboveLimit ) ] ;
164
209
}
165
210
166
211
function isGitpodIo ( ) {
@@ -169,7 +214,7 @@ function isGitpodIo() {
169
214
170
215
function Card ( p : { className ?: string ; children ?: React . ReactNode } ) {
171
216
return (
172
- < div className = { "flex rounded-xl font-semibold text-base w-72 h-64 px-4 " + ( p . className || "" ) } >
217
+ < div className = { "flex rounded-xl text-base w-72 h-64 px-4 " + ( p . className || "" ) } >
173
218
< span > { p . children } </ span >
174
219
</ div >
175
220
) ;
0 commit comments