1
1
import type { Interpolation , Theme } from "@emotion/react" ;
2
2
import ArrowForwardOutlined from "@mui/icons-material/ArrowForwardOutlined" ;
3
3
import Button from "@mui/material/Button" ;
4
+ import Link from "@mui/material/Link" ;
5
+ import Tooltip from "@mui/material/Tooltip" ;
6
+ import { visuallyHidden } from "@mui/utils" ;
4
7
import type { FC , HTMLAttributes } from "react" ;
5
8
import { Link as RouterLink , useNavigate } from "react-router-dom" ;
6
9
import type { Template } from "api/typesGenerated" ;
7
- import { ExternalAvatar } from "components/Avatar/Avatar" ;
10
+ import { ExternalAvatar , Avatar } from "components/Avatar/Avatar" ;
8
11
import { AvatarData } from "components/AvatarData/AvatarData" ;
9
12
import { DeprecatedBadge } from "components/Badges/Badges" ;
13
+ import { ExternalImage } from "components/ExternalImage/ExternalImage" ;
14
+ import { Pill } from "components/Pill/Pill" ;
15
+ import { formatTemplateBuildTime } from "utils/templates" ;
10
16
11
17
type TemplateCardProps = HTMLAttributes < HTMLDivElement > & {
12
18
template : Template ;
19
+ activeOrg ?: string ;
20
+ hasMultipleOrgs : boolean ;
13
21
} ;
14
22
15
23
export const TemplateCard : FC < TemplateCardProps > = ( {
16
24
template,
25
+ activeOrg,
26
+ hasMultipleOrgs,
17
27
...divProps
18
28
} ) => {
19
29
const navigate = useNavigate ( ) ;
@@ -25,7 +35,6 @@ export const TemplateCard: FC<TemplateCardProps> = ({
25
35
navigate ( templatePageLink ) ;
26
36
}
27
37
} ;
28
-
29
38
return (
30
39
< div
31
40
css = { styles . card }
@@ -36,52 +45,78 @@ export const TemplateCard: FC<TemplateCardProps> = ({
36
45
onKeyDown = { handleKeyDown }
37
46
>
38
47
< div css = { styles . header } >
39
- < div >
48
+ < div css = { { display : "flex" , alignItems : "center" } } >
40
49
< AvatarData
50
+ displayTitle = { false }
51
+ subtitle = ""
41
52
title = {
42
53
template . display_name . length > 0
43
54
? template . display_name
44
55
: template . name
45
56
}
46
- subtitle = { template . organization_display_name }
47
- avatar = {
48
- hasIcon && (
49
- < ExternalAvatar variant = "square" fitImage src = { template . icon } />
50
- )
51
- }
57
+ avatar = { hasIcon && < Avatar src = { template . icon } size = "xl" /> }
52
58
/>
59
+ < p
60
+ css = { ( theme ) => ( {
61
+ fontSize : 13 ,
62
+ margin : "0 0 0 auto" ,
63
+ color : theme . palette . text . secondary ,
64
+ } ) }
65
+ >
66
+ < span css = { { ...visuallyHidden } } > Build time: </ span >
67
+ < Tooltip title = "Build time" placement = "bottom-start" >
68
+ < span >
69
+ { formatTemplateBuildTime ( template . build_time_stats . start . P50 ) }
70
+ </ span >
71
+ </ Tooltip >
72
+ </ p >
53
73
</ div >
54
- < div >
55
- { template . active_user_count } { " " }
56
- { template . active_user_count === 1 ? "user" : "users" }
57
- </ div >
74
+
75
+ { hasMultipleOrgs && (
76
+ < div css = { styles . orgs } >
77
+ < RouterLink
78
+ to = { `/organizations/${ template . organization_name } ` }
79
+ onClick = { ( e ) => e . stopPropagation ( ) }
80
+ >
81
+ < Pill
82
+ css = { [
83
+ styles . org ,
84
+ activeOrg === template . organization_id && styles . activeOrg ,
85
+ ] }
86
+ >
87
+ { template . organization_display_name }
88
+ </ Pill >
89
+ </ RouterLink >
90
+ </ div >
91
+ ) }
58
92
</ div >
59
93
60
94
< div >
95
+ < h4 css = { { fontSize : 14 , fontWeight : 600 , margin : 0 , marginBottom : 4 } } >
96
+ { template . display_name }
97
+ </ h4 >
61
98
< span css = { styles . description } >
62
- < p > { template . description } </ p >
99
+ { template . description } { " " }
100
+ < Link
101
+ component = { RouterLink }
102
+ onClick = { ( e ) => e . stopPropagation ( ) }
103
+ to = { `/templates/${ template . name } /docs` }
104
+ css = { { display : "inline-block" , fontSize : 13 , marginTop : 4 } }
105
+ >
106
+ Read more
107
+ </ Link >
63
108
</ span >
64
109
</ div >
65
110
66
111
< div css = { styles . useButtonContainer } >
67
- { template . deprecated ? (
68
- < DeprecatedBadge />
69
- ) : (
70
- < Button
71
- component = { RouterLink }
72
- css = { styles . actionButton }
73
- className = "actionButton"
74
- fullWidth
75
- startIcon = { < ArrowForwardOutlined /> }
76
- title = { `Create a workspace using the ${ template . display_name } template` }
77
- to = { `/templates/${ template . name } /workspace` }
78
- onClick = { ( e ) => {
79
- e . stopPropagation ( ) ;
80
- } }
81
- >
82
- Create Workspace
83
- </ Button >
84
- ) }
112
+ < Button
113
+ component = { RouterLink }
114
+ onClick = { ( e ) => e . stopPropagation ( ) }
115
+ fullWidth
116
+ to = { `/templates/${ template . name } /workspace` }
117
+ >
118
+ Use template
119
+ </ Button >
85
120
</ div >
86
121
</ div >
87
122
) ;
@@ -141,4 +176,25 @@ const styles = {
141
176
borderColor : theme . palette . text . primary ,
142
177
} ,
143
178
} ) ,
179
+
180
+ orgs : {
181
+ display : "flex" ,
182
+ flexWrap : "wrap" ,
183
+ gap : 8 ,
184
+ justifyContent : "end" ,
185
+ } ,
186
+
187
+ org : ( theme ) => ( {
188
+ borderColor : theme . palette . divider ,
189
+ textDecoration : "none" ,
190
+ cursor : "pointer" ,
191
+ "&: hover" : {
192
+ borderColor : theme . palette . primary . main ,
193
+ } ,
194
+ } ) ,
195
+
196
+ activeOrg : ( theme ) => ( {
197
+ borderColor : theme . roles . active . outline ,
198
+ backgroundColor : theme . roles . active . background ,
199
+ } ) ,
144
200
} satisfies Record < string , Interpolation < Theme > > ;
0 commit comments