|
1 |
| -import { useTheme } from "@emotion/react"; |
| 1 | +import { type Interpolation, type Theme, useTheme } from "@emotion/react"; |
2 | 2 | import ArrowBackOutlined from "@mui/icons-material/ArrowBackOutlined";
|
3 | 3 | import DeleteOutline from "@mui/icons-material/DeleteOutline";
|
4 | 4 | import QuotaIcon from "@mui/icons-material/MonetizationOnOutlined";
|
@@ -132,174 +132,37 @@ export const WorkspaceTopbar: FC<WorkspaceProps> = ({
|
132 | 132 | </TopbarIconButton>
|
133 | 133 | </Tooltip>
|
134 | 134 |
|
135 |
| - <div |
136 |
| - css={{ |
137 |
| - display: "flex", |
138 |
| - alignItems: "center", |
139 |
| - columnGap: 24, |
140 |
| - rowGap: 8, |
141 |
| - flexWrap: "wrap", |
142 |
| - // 12px - It is needed to keep vertical spacing when the content is wrapped |
143 |
| - padding: "12px", |
144 |
| - marginRight: "auto", |
145 |
| - }} |
146 |
| - > |
| 135 | + <div css={styles.topbarLeft}> |
147 | 136 | <TopbarData>
|
148 |
| - <Popover mode="hover"> |
149 |
| - <PopoverTrigger> |
150 |
| - <span |
151 |
| - css={{ |
152 |
| - display: "flex", |
153 |
| - flexFlow: "row nowrap", |
154 |
| - gap: "8px", |
155 |
| - maxWidth: "160px", |
156 |
| - textOverflow: "ellipsis", |
157 |
| - overflowX: "hidden", |
158 |
| - whiteSpace: "nowrap", |
159 |
| - cursor: "default", |
160 |
| - }} |
161 |
| - > |
162 |
| - <UserAvatar |
163 |
| - size="xs" |
164 |
| - username={workspace.owner_name} |
165 |
| - avatarURL={workspace.owner_avatar_url} |
166 |
| - /> |
167 |
| - |
168 |
| - {workspace.owner_name} |
169 |
| - </span> |
170 |
| - </PopoverTrigger> |
171 |
| - |
172 |
| - <HelpTooltipContent |
173 |
| - anchorOrigin={{ vertical: "bottom", horizontal: "center" }} |
174 |
| - transformOrigin={{ vertical: "top", horizontal: "center" }} |
175 |
| - > |
176 |
| - <AvatarData |
177 |
| - title={workspace.owner_name} |
178 |
| - subtitle="Owner" |
179 |
| - avatar={workspace.owner_avatar_url} |
180 |
| - /> |
181 |
| - </HelpTooltipContent> |
182 |
| - </Popover> |
| 137 | + <OwnerBreadcrumb |
| 138 | + ownerName={workspace.owner_name} |
| 139 | + ownerAvatarUrl={workspace.owner_avatar_url} |
| 140 | + /> |
183 | 141 |
|
184 | 142 | {showOrganizations && (
|
185 | 143 | <>
|
186 | 144 | <TopbarDivider />
|
187 |
| - |
188 |
| - <Popover mode="hover"> |
189 |
| - <PopoverTrigger> |
190 |
| - <span |
191 |
| - css={{ |
192 |
| - display: "flex", |
193 |
| - flexFlow: "row nowrap", |
194 |
| - gap: "8px", |
195 |
| - maxWidth: "160px", |
196 |
| - textOverflow: "ellipsis", |
197 |
| - overflowX: "hidden", |
198 |
| - whiteSpace: "nowrap", |
199 |
| - cursor: "default", |
200 |
| - }} |
201 |
| - > |
202 |
| - {activeOrg && ( |
203 |
| - <UserAvatar |
204 |
| - size="xs" |
205 |
| - username={activeOrg.display_name} |
206 |
| - avatarURL={activeOrg.icon} |
207 |
| - /> |
208 |
| - )} |
209 |
| - |
210 |
| - {workspace.organization_name} |
211 |
| - </span> |
212 |
| - </PopoverTrigger> |
213 |
| - |
214 |
| - <HelpTooltipContent |
215 |
| - anchorOrigin={{ vertical: "bottom", horizontal: "center" }} |
216 |
| - transformOrigin={{ vertical: "top", horizontal: "center" }} |
217 |
| - > |
218 |
| - <AvatarData |
219 |
| - title={ |
220 |
| - showOrganizations ? ( |
221 |
| - <Link |
222 |
| - component={RouterLink} |
223 |
| - to={`/organizations/${encodeURIComponent(workspace.organization_name)}`} |
224 |
| - css={{ color: "inherit" }} |
225 |
| - > |
226 |
| - {workspace.organization_name} |
227 |
| - </Link> |
228 |
| - ) : ( |
229 |
| - workspace.organization_name |
230 |
| - ) |
231 |
| - } |
232 |
| - subtitle="Organization" |
233 |
| - avatar={ |
234 |
| - activeOrg !== undefined && ( |
235 |
| - <ExternalAvatar |
236 |
| - src={activeOrg.icon} |
237 |
| - variant="square" |
238 |
| - fitImage |
239 |
| - /> |
240 |
| - ) |
241 |
| - } |
242 |
| - /> |
243 |
| - </HelpTooltipContent> |
244 |
| - </Popover> |
| 145 | + <OrganizationBreadcrumb |
| 146 | + orgName={workspace.organization_name} |
| 147 | + orgIconUrl={activeOrg?.icon} |
| 148 | + orgPageUrl={ |
| 149 | + showOrganizations |
| 150 | + ? `/organizations/${encodeURIComponent(workspace.organization_name)}` |
| 151 | + : undefined |
| 152 | + } |
| 153 | + /> |
245 | 154 | </>
|
246 | 155 | )}
|
247 | 156 |
|
248 | 157 | <TopbarDivider />
|
249 | 158 |
|
250 |
| - <Popover mode="hover"> |
251 |
| - <PopoverTrigger> |
252 |
| - <span |
253 |
| - css={{ |
254 |
| - display: "flex", |
255 |
| - alignItems: "center", |
256 |
| - gap: 8, |
257 |
| - cursor: "default", |
258 |
| - padding: "4px 0", |
259 |
| - }} |
260 |
| - > |
261 |
| - <TopbarAvatar src={workspace.template_icon} /> |
262 |
| - <span css={{ fontWeight: 500 }}>{workspace.name}</span> |
263 |
| - </span> |
264 |
| - </PopoverTrigger> |
265 |
| - |
266 |
| - <HelpTooltipContent |
267 |
| - anchorOrigin={{ vertical: "bottom", horizontal: "center" }} |
268 |
| - transformOrigin={{ vertical: "top", horizontal: "center" }} |
269 |
| - > |
270 |
| - <AvatarData |
271 |
| - title={ |
272 |
| - <Link |
273 |
| - component={RouterLink} |
274 |
| - to={templateLink} |
275 |
| - css={{ color: "inherit" }} |
276 |
| - > |
277 |
| - {workspace.template_display_name.length > 0 |
278 |
| - ? workspace.template_display_name |
279 |
| - : workspace.template_name} |
280 |
| - </Link> |
281 |
| - } |
282 |
| - subtitle={ |
283 |
| - <Link |
284 |
| - component={RouterLink} |
285 |
| - to={`${templateLink}/versions/${workspace.latest_build.template_version_name}`} |
286 |
| - css={{ color: "inherit" }} |
287 |
| - > |
288 |
| - Version: {workspace.latest_build.template_version_name} |
289 |
| - </Link> |
290 |
| - } |
291 |
| - avatar={ |
292 |
| - workspace.template_icon !== "" && ( |
293 |
| - <ExternalAvatar |
294 |
| - src={workspace.template_icon} |
295 |
| - variant="square" |
296 |
| - fitImage |
297 |
| - /> |
298 |
| - ) |
299 |
| - } |
300 |
| - /> |
301 |
| - </HelpTooltipContent> |
302 |
| - </Popover> |
| 159 | + <WorkspaceBreadcrumb |
| 160 | + workspaceName={workspace.name} |
| 161 | + templateIconUrl={workspace.template_icon} |
| 162 | + rootTemplateUrl={templateLink} |
| 163 | + templateVersionName={workspace.template_name} |
| 164 | + templateVersionDisplayName={workspace.template_display_name} |
| 165 | + /> |
303 | 166 | </TopbarData>
|
304 | 167 |
|
305 | 168 | {quota && quota.budget > 0 && (
|
@@ -406,3 +269,178 @@ export const WorkspaceTopbar: FC<WorkspaceProps> = ({
|
406 | 269 | </Topbar>
|
407 | 270 | );
|
408 | 271 | };
|
| 272 | + |
| 273 | +type OwnerBreadcrumbProps = Readonly<{ |
| 274 | + ownerName: string; |
| 275 | + ownerAvatarUrl: string; |
| 276 | +}>; |
| 277 | + |
| 278 | +const OwnerBreadcrumb: FC<OwnerBreadcrumbProps> = ({ |
| 279 | + ownerName, |
| 280 | + ownerAvatarUrl, |
| 281 | +}) => { |
| 282 | + return ( |
| 283 | + <Popover mode="hover"> |
| 284 | + <PopoverTrigger> |
| 285 | + <span css={styles.breadcrumbSegment}> |
| 286 | + <UserAvatar |
| 287 | + size="xs" |
| 288 | + username={ownerName} |
| 289 | + avatarURL={ownerAvatarUrl} |
| 290 | + /> |
| 291 | + |
| 292 | + {ownerName} |
| 293 | + </span> |
| 294 | + </PopoverTrigger> |
| 295 | + |
| 296 | + <HelpTooltipContent |
| 297 | + anchorOrigin={{ vertical: "bottom", horizontal: "center" }} |
| 298 | + transformOrigin={{ vertical: "top", horizontal: "center" }} |
| 299 | + > |
| 300 | + <AvatarData |
| 301 | + title={ownerName} |
| 302 | + subtitle="Owner" |
| 303 | + avatar={ownerAvatarUrl} |
| 304 | + /> |
| 305 | + </HelpTooltipContent> |
| 306 | + </Popover> |
| 307 | + ); |
| 308 | +}; |
| 309 | + |
| 310 | +type OrganizationBreadcrumbProps = Readonly<{ |
| 311 | + orgName: string; |
| 312 | + orgPageUrl?: string; |
| 313 | + orgIconUrl?: string; |
| 314 | +}>; |
| 315 | + |
| 316 | +const OrganizationBreadcrumb: FC<OrganizationBreadcrumbProps> = ({ |
| 317 | + orgName, |
| 318 | + orgPageUrl, |
| 319 | + orgIconUrl, |
| 320 | +}) => { |
| 321 | + return ( |
| 322 | + <Popover mode="hover"> |
| 323 | + <PopoverTrigger> |
| 324 | + <span css={styles.breadcrumbSegment}> |
| 325 | + <UserAvatar size="xs" src={orgIconUrl ?? ""} username={orgName} /> |
| 326 | + {orgName} |
| 327 | + </span> |
| 328 | + </PopoverTrigger> |
| 329 | + |
| 330 | + <HelpTooltipContent |
| 331 | + anchorOrigin={{ vertical: "bottom", horizontal: "center" }} |
| 332 | + transformOrigin={{ vertical: "top", horizontal: "center" }} |
| 333 | + > |
| 334 | + <AvatarData |
| 335 | + title={ |
| 336 | + orgPageUrl ? ( |
| 337 | + <Link |
| 338 | + component={RouterLink} |
| 339 | + to={orgPageUrl} |
| 340 | + css={{ color: "inherit" }} |
| 341 | + > |
| 342 | + {orgName} |
| 343 | + </Link> |
| 344 | + ) : ( |
| 345 | + orgName |
| 346 | + ) |
| 347 | + } |
| 348 | + subtitle="Organization" |
| 349 | + avatar={ |
| 350 | + orgIconUrl && ( |
| 351 | + <ExternalAvatar src={orgIconUrl} variant="square" fitImage /> |
| 352 | + ) |
| 353 | + } |
| 354 | + /> |
| 355 | + </HelpTooltipContent> |
| 356 | + </Popover> |
| 357 | + ); |
| 358 | +}; |
| 359 | + |
| 360 | +type WorkspaceBreadcrumbProps = Readonly<{ |
| 361 | + workspaceName: string; |
| 362 | + templateIconUrl: string; |
| 363 | + rootTemplateUrl: string; |
| 364 | + templateVersionName: string; |
| 365 | + templateVersionDisplayName?: string; |
| 366 | +}>; |
| 367 | + |
| 368 | +const WorkspaceBreadcrumb: FC<WorkspaceBreadcrumbProps> = ({ |
| 369 | + workspaceName, |
| 370 | + templateIconUrl, |
| 371 | + rootTemplateUrl, |
| 372 | + templateVersionName, |
| 373 | + templateVersionDisplayName = templateVersionName, |
| 374 | +}) => { |
| 375 | + return ( |
| 376 | + <Popover mode="hover"> |
| 377 | + <PopoverTrigger> |
| 378 | + <span |
| 379 | + css={{ |
| 380 | + display: "flex", |
| 381 | + alignItems: "center", |
| 382 | + gap: 8, |
| 383 | + cursor: "default", |
| 384 | + padding: "4px 0", |
| 385 | + }} |
| 386 | + > |
| 387 | + <TopbarAvatar src={templateIconUrl} /> |
| 388 | + <span css={{ fontWeight: 500 }}>{workspaceName}</span> |
| 389 | + </span> |
| 390 | + </PopoverTrigger> |
| 391 | + |
| 392 | + <HelpTooltipContent |
| 393 | + anchorOrigin={{ vertical: "bottom", horizontal: "center" }} |
| 394 | + transformOrigin={{ vertical: "top", horizontal: "center" }} |
| 395 | + > |
| 396 | + <AvatarData |
| 397 | + title={ |
| 398 | + <Link |
| 399 | + component={RouterLink} |
| 400 | + to={rootTemplateUrl} |
| 401 | + css={{ color: "inherit" }} |
| 402 | + > |
| 403 | + {templateVersionDisplayName} |
| 404 | + </Link> |
| 405 | + } |
| 406 | + subtitle={ |
| 407 | + <Link |
| 408 | + component={RouterLink} |
| 409 | + to={`${rootTemplateUrl}/versions/${encodeURIComponent(templateVersionName)}`} |
| 410 | + css={{ color: "inherit" }} |
| 411 | + > |
| 412 | + Version: {templateVersionDisplayName} |
| 413 | + </Link> |
| 414 | + } |
| 415 | + avatar={ |
| 416 | + <ExternalAvatar src={templateIconUrl} variant="square" fitImage /> |
| 417 | + } |
| 418 | + /> |
| 419 | + </HelpTooltipContent> |
| 420 | + </Popover> |
| 421 | + ); |
| 422 | +}; |
| 423 | + |
| 424 | +const styles = { |
| 425 | + topbarLeft: { |
| 426 | + display: "flex", |
| 427 | + alignItems: "center", |
| 428 | + columnGap: 24, |
| 429 | + rowGap: 8, |
| 430 | + flexWrap: "wrap", |
| 431 | + // 12px - It is needed to keep vertical spacing when the content is wrapped |
| 432 | + padding: "12px", |
| 433 | + marginRight: "auto", |
| 434 | + }, |
| 435 | + |
| 436 | + breadcrumbSegment: { |
| 437 | + display: "flex", |
| 438 | + flexFlow: "row nowrap", |
| 439 | + gap: "8px", |
| 440 | + maxWidth: "160px", |
| 441 | + textOverflow: "ellipsis", |
| 442 | + overflowX: "hidden", |
| 443 | + whiteSpace: "nowrap", |
| 444 | + cursor: "default", |
| 445 | + }, |
| 446 | +} satisfies Record<string, Interpolation<Theme>>; |
0 commit comments