go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/milo/ui/src/build/pages/builder_page/builder_health_indicator.tsx (about) 1 // Copyright 2023 The LUCI Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 import { Link } from '@mui/material'; 16 17 import { useAuthState } from '@/common/components/auth_state_provider'; 18 import { HealthStatus } from '@/common/services/buildbucket'; 19 20 interface BuilderHealthIndicatorProps { 21 readonly healthStatus?: HealthStatus; 22 } 23 24 const SCORE_COLOR_MAP: { [score: string]: string } = Object.freeze({ 25 '0': 'var(--greyed-out-text-color)', 26 '1': 'var(--failure-color)', 27 ...Object.fromEntries( 28 Array(8) 29 .fill(0) 30 .map((_, i) => [`${i + 2}`, 'var(--warning-color)']), 31 ), 32 '10': 'var(--success-color)', 33 }); 34 35 const TEXT_MAP: { [key: string]: string } = Object.freeze({ 36 '0': 'Not set', 37 '1': 'Low Value', 38 ...Object.fromEntries( 39 Array(3) 40 .fill(0) 41 .map((_, i) => [`${i + 2}`, 'Very unhealthy']), 42 ), 43 '5': 'Unhealthy', 44 ...Object.fromEntries( 45 Array(4) 46 .fill(0) 47 .map((_, i) => [`${i + 6}`, 'Slightly unhealthy']), 48 ), 49 '10': 'Healthy', 50 }); 51 52 export function BuilderHealthIndicator({ 53 healthStatus, 54 }: BuilderHealthIndicatorProps) { 55 const authState = useAuthState(); 56 57 if (!healthStatus) { 58 return <></>; 59 } 60 61 return ( 62 <> 63 <div 64 css={{ 65 display: 'flex', 66 flex: '0 auto', 67 position: 'relative', // Machine Pool has padding that obscures the bottom half of the link without this 68 }} 69 > 70 <div id="health-indicator"> 71 <span css={{ color: 'var(--light-text-color)' }}>Health </span> 72 <Link href={linkUrl(healthStatus.dataLinks, authState.email)}> 73 <span 74 id="health-text" 75 style={{ 76 color: 77 SCORE_COLOR_MAP[healthStatus.healthScore || '0'] || 78 '--critical-failure-color', 79 }} 80 title={healthStatus.description || ''} 81 > 82 {TEXT_MAP[healthStatus.healthScore || '0'] || 83 `Unknown health ${healthStatus.healthScore}`} 84 </span> 85 </Link> 86 </div> 87 </div> 88 </> 89 ); 90 } 91 92 function linkUrl( 93 dataLinks?: { [key: string]: string }, 94 authEmail?: string, 95 ): string { 96 if (!dataLinks) { 97 return ''; 98 } 99 const userDomain = authEmail?.split('@').at(-1) || ''; 100 return dataLinks[userDomain] || dataLinks[''] || ''; 101 }