github.com/thanos-io/thanos@v0.32.5/pkg/ui/react-app/src/pages/alerts/CollapsibleAlertPanel.tsx (about) 1 import React, { FC, useState, Fragment } from 'react'; 2 import { Alert, Collapse, Table, Badge } from 'reactstrap'; 3 import { RuleStatus } from './AlertContents'; 4 import { Rule } from '../../types/types'; 5 import { faChevronDown, faChevronRight } from '@fortawesome/free-solid-svg-icons'; 6 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; 7 import { createExternalExpressionLink, formatDuration } from '../../utils/index'; 8 9 interface CollapsibleAlertPanelProps { 10 rule: Rule; 11 showAnnotations: boolean; 12 } 13 14 const alertColors: RuleStatus<string> = { 15 firing: 'danger', 16 pending: 'warning', 17 inactive: 'success', 18 }; 19 20 const CollapsibleAlertPanel: FC<CollapsibleAlertPanelProps> = ({ rule, showAnnotations }) => { 21 const [open, toggle] = useState(false); 22 23 return ( 24 <> 25 <Alert fade={false} onClick={() => toggle(!open)} color={alertColors[rule.state]} style={{ cursor: 'pointer' }}> 26 <FontAwesomeIcon icon={open ? faChevronDown : faChevronRight} fixedWidth /> 27 <strong>{rule.name}</strong> ({`${rule.alerts.length} active`}) 28 </Alert> 29 <Collapse isOpen={open} className="mb-2"> 30 <pre className="alert-cell"> 31 <code> 32 <div> 33 name: <a href={createExternalExpressionLink(`ALERTS{alertname="${rule.name}"}`)}>{rule.name}</a> 34 </div> 35 <div> 36 expr: <a href={createExternalExpressionLink(rule.query)}>{rule.query}</a> 37 </div> 38 {rule.duration > 0 && ( 39 <div> 40 <div>for: {formatDuration(rule.duration * 1000)}</div> 41 </div> 42 )} 43 {rule.labels && Object.keys(rule.labels).length > 0 && ( 44 <div> 45 <div>labels:</div> 46 {Object.entries(rule.labels).map(([key, value]) => ( 47 <div className="ml-4" key={key}> 48 {key}: {value} 49 </div> 50 ))} 51 </div> 52 )} 53 {rule.annotations && Object.keys(rule.annotations).length > 0 && ( 54 <div> 55 <div>annotations:</div> 56 {Object.entries(rule.annotations).map(([key, value]) => ( 57 <div className="ml-4" key={key}> 58 {key}: {value} 59 </div> 60 ))} 61 </div> 62 )} 63 </code> 64 </pre> 65 {rule.alerts.length > 0 && ( 66 <Table bordered size="sm"> 67 <thead> 68 <tr> 69 <th>Labels</th> 70 <th>State</th> 71 <th>Active Since</th> 72 <th>Value</th> 73 </tr> 74 </thead> 75 <tbody> 76 {rule.alerts.map((alert, i) => { 77 return ( 78 <Fragment key={i}> 79 <tr> 80 <td style={{ verticalAlign: 'middle' }}> 81 {Object.entries(alert.labels).map(([k, v], j) => { 82 return ( 83 <Badge key={j} color="primary" className="mr-1"> 84 {k}={v} 85 </Badge> 86 ); 87 })} 88 </td> 89 <td> 90 <h5 className="m-0"> 91 <Badge color={alertColors[alert.state] + ' text-uppercase'} className="px-3"> 92 {alert.state} 93 </Badge> 94 </h5> 95 </td> 96 <td>{alert.activeAt}</td> 97 <td>{alert.value}</td> 98 </tr> 99 {showAnnotations && <Annotations annotations={alert.annotations} />} 100 </Fragment> 101 ); 102 })} 103 </tbody> 104 </Table> 105 )} 106 </Collapse> 107 </> 108 ); 109 }; 110 111 interface AnnotationsProps { 112 annotations: Record<string, string>; 113 } 114 115 export const Annotations: FC<AnnotationsProps> = ({ annotations }) => { 116 return ( 117 <Fragment> 118 <tr> 119 <td colSpan={4}> 120 <h5 className="font-weight-bold">Annotations</h5> 121 </td> 122 </tr> 123 <tr> 124 <td colSpan={4}> 125 {Object.entries(annotations).map(([k, v], i) => { 126 return ( 127 <div key={i}> 128 <strong>{k}</strong> 129 <div>{v}</div> 130 </div> 131 ); 132 })} 133 </td> 134 </tr> 135 </Fragment> 136 ); 137 }; 138 139 export default CollapsibleAlertPanel;