@@ -31,6 +31,8 @@ import dayjs from "dayjs"
3131import { ReactElement , ReactNode , cloneElement , useMemo } from "react"
3232import { WorkspaceStatus } from "./WorkspaceStatus"
3333import { ManagementV1DevPodWorkspaceInstanceKubernetesStatus } from "@loft-enterprise/client/gen/models/managementV1DevPodWorkspaceInstanceKubernetesStatus"
34+ import { ManagementV1DevPodWorkspaceInstancePodStatus , ManagementV1DevPodWorkspaceInstancePodStatusPhaseEnum } from "@loft-enterprise/client/gen/models/managementV1DevPodWorkspaceInstancePodStatus"
35+ import { ManagementV1DevPodWorkspaceInstancePersistentVolumeClaimStatus , ManagementV1DevPodWorkspaceInstancePersistentVolumeClaimStatusPhaseEnum } from "@loft-enterprise/client/gen/models/managementV1DevPodWorkspaceInstancePersistentVolumeClaimStatus"
3436import { quantityToScalar } from "@kubernetes/client-node/dist/util"
3537
3638type TWorkspaceDetailsProps = Readonly < {
@@ -359,13 +361,13 @@ function KubernetesDetails({ status }: TKubernetesDetailsProps) {
359361 }
360362 }
361363
362- if ( ! mainContainerResources . resources ?. requests ) {
364+ if ( ! mainContainerResources . resources ?. limits ) {
363365 return Object . entries ( mainContainerMetrics ?. usage ?? { } ) . map ( ( [ type , quantity ] ) => {
364366 return getResourceDetails ( type , undefined , quantity , undefined )
365367 } )
366368 }
367369
368- return Object . entries ( mainContainerResources . resources ?. requests ?? { } ) . map (
370+ return Object . entries ( mainContainerResources . resources ?. limits ?? { } ) . map (
369371 ( [ type , quantity ] ) => {
370372 const used = indexedMetrics [ type ]
371373 let usagePercentage = calculateUsagePercentage (
@@ -386,6 +388,9 @@ function KubernetesDetails({ status }: TKubernetesDetailsProps) {
386388 </ StackedWorkspaceInfoDetail >
387389 ) }
388390
391+ { status . podStatus && < PodStatus podStatus = { status . podStatus } /> }
392+ { status . persistentVolumeClaimStatus && < PvcStatus pvcStatus = { status . persistentVolumeClaimStatus } /> }
393+
389394 { resources . map ( ( resource ) => {
390395 return (
391396 < StackedWorkspaceInfoDetail
@@ -415,6 +420,120 @@ function KubernetesDetails({ status }: TKubernetesDetailsProps) {
415420 )
416421}
417422
423+ function PodStatus ( { podStatus } : { podStatus : ManagementV1DevPodWorkspaceInstancePodStatus } ) {
424+ const phase = podStatus . phase
425+ const phaseColor = {
426+ [ ManagementV1DevPodWorkspaceInstancePodStatusPhaseEnum . Pending ] : "yellow.500" ,
427+ [ ManagementV1DevPodWorkspaceInstancePodStatusPhaseEnum . Running ] : "" ,
428+ [ ManagementV1DevPodWorkspaceInstancePodStatusPhaseEnum . Succeeded ] : "red.400" ,
429+ [ ManagementV1DevPodWorkspaceInstancePodStatusPhaseEnum . Failed ] : "red.400" ,
430+ [ ManagementV1DevPodWorkspaceInstancePodStatusPhaseEnum . Unknown ] : "red.400" ,
431+ }
432+
433+ let reason = podStatus . reason
434+ let message = podStatus . message
435+ if ( phase !== ManagementV1DevPodWorkspaceInstancePodStatusPhaseEnum . Running ) {
436+ // check container status first
437+ const containerStatus = podStatus . containerStatuses ?. find ( ( container ) => container . name === "devpod" && ( container . state ?. waiting ?. reason || container . state ?. terminated ?. reason ) )
438+ if ( containerStatus ) {
439+ if ( containerStatus . state ?. waiting ) {
440+ reason = containerStatus . state . waiting . reason
441+ message = containerStatus . state . waiting . message
442+ } else if ( containerStatus . state ?. terminated ) {
443+ reason = containerStatus . state . terminated . reason
444+ message = containerStatus . state . terminated . message
445+ if ( ! containerStatus . state . terminated . message && containerStatus . state . terminated . exitCode != 0 ) {
446+ message = "Exit code: " + containerStatus . state . terminated . exitCode
447+ }
448+ }
449+ }
450+
451+ // check pod conditions
452+ if ( ! reason && ! message ) {
453+ const podCondition = podStatus . conditions ?. find ( ( condition ) => condition . status === "False" && condition . reason )
454+ if ( podCondition ) {
455+ reason = podCondition . reason
456+ message = podCondition . message
457+ }
458+ }
459+
460+ // try to find warning event
461+ if ( ! reason && ! message ) {
462+ const warningEvent = podStatus . events ?. find ( ( event ) => event . type === "Warning" )
463+ if ( warningEvent ) {
464+ reason = warningEvent . reason
465+ message = warningEvent . message
466+ }
467+ }
468+
469+ // try to find normal event
470+ if ( ! reason && ! message ) {
471+ const normalEvent = podStatus . events ?. find ( ( event ) => event . type === "Normal" )
472+ if ( normalEvent ) {
473+ reason = normalEvent . reason
474+ message = normalEvent . message
475+ }
476+ }
477+ }
478+
479+ return (
480+ < StackedWorkspaceInfoDetail icon = { Dashboard } label = { < Text > Pod</ Text > } >
481+ < Text color = { phase ? phaseColor [ phase ] : "gray.500" } >
482+ { phase === ManagementV1DevPodWorkspaceInstancePodStatusPhaseEnum . Running ? podStatus . phase : (
483+ ( reason && message ) ? < Tooltip label = { message } >
484+ < Text > { podStatus . phase } ({ reason } )</ Text >
485+ </ Tooltip > : ( reason ? < Text > { podStatus . phase } ({ reason } )</ Text > : podStatus . phase )
486+ ) }
487+ </ Text >
488+ </ StackedWorkspaceInfoDetail >
489+ )
490+ }
491+
492+
493+ function PvcStatus ( { pvcStatus } : { pvcStatus : ManagementV1DevPodWorkspaceInstancePersistentVolumeClaimStatus } ) {
494+ const phase = pvcStatus . phase
495+ const phaseColor = {
496+ [ ManagementV1DevPodWorkspaceInstancePersistentVolumeClaimStatusPhaseEnum . Pending ] : "yellow.500" ,
497+ [ ManagementV1DevPodWorkspaceInstancePersistentVolumeClaimStatusPhaseEnum . Bound ] : "" ,
498+ [ ManagementV1DevPodWorkspaceInstancePersistentVolumeClaimStatusPhaseEnum . Lost ] : "red.400" ,
499+ }
500+
501+ let reason : string | undefined = ""
502+ let message : string | undefined = ""
503+ if ( phase !== ManagementV1DevPodWorkspaceInstancePersistentVolumeClaimStatusPhaseEnum . Bound ) {
504+ reason = pvcStatus . conditions ?. find ( ( condition ) => condition . status === "False" ) ?. reason
505+ message = pvcStatus . conditions ?. find ( ( condition ) => condition . status === "False" ) ?. message
506+
507+ // try to find warning event
508+ if ( ! reason && ! message ) {
509+ const warningEvent = pvcStatus . events ?. find ( ( event ) => event . type === "Warning" )
510+ if ( warningEvent ) {
511+ reason = warningEvent . reason
512+ message = warningEvent . message
513+ }
514+ }
515+
516+ // try to find normal event
517+ if ( ! reason && ! message ) {
518+ const normalEvent = pvcStatus . events ?. find ( ( event ) => event . type === "Normal" )
519+ if ( normalEvent ) {
520+ reason = normalEvent . reason
521+ message = normalEvent . message
522+ }
523+ }
524+ }
525+
526+ return (
527+ < StackedWorkspaceInfoDetail icon = { Dashboard } label = { < Text > Volume</ Text > } >
528+ < Text color = { phase ? phaseColor [ phase ] : "gray.500" } >
529+ { phase === ManagementV1DevPodWorkspaceInstancePersistentVolumeClaimStatusPhaseEnum . Bound ? pvcStatus . phase : ( ( reason && message ) ? < Tooltip label = { message } >
530+ < Text > { pvcStatus . phase } ({ reason } )</ Text >
531+ </ Tooltip > : reason ? < Text > { pvcStatus . phase } ({ reason } )</ Text > : pvcStatus . phase ) }
532+ </ Text >
533+ </ StackedWorkspaceInfoDetail >
534+ )
535+ }
536+
418537const invalidQuantity = - 1
419538
420539function quantityToScalarBigInt ( quantity : string | number | undefined ) : bigint | number {
0 commit comments