prometheus/web/ui/react-app/src/pages/alerts/AlertContents.tsx

137 lines
3.5 KiB
TypeScript
Raw Normal View History

React UI: Implement alerts page (#6402) * url filter rules param Signed-off-by: blalov <boiskila@gmail.com> Signed-off-by: Boyko Lalov <boiskila@gmail.com> Signed-off-by: blalov <boiskila@gmail.com> * address review changes Signed-off-by: blalov <boiskila@gmail.com> Signed-off-by: Boyko Lalov <boiskila@gmail.com> Signed-off-by: blalov <boiskila@gmail.com> * ui initial commit Signed-off-by: blalov <boiskila@gmail.com> Signed-off-by: Boyko Lalov <boiskila@gmail.com> Signed-off-by: blalov <boiskila@gmail.com> * improve ui Signed-off-by: blalov <boiskila@gmail.com> Signed-off-by: Boyko Lalov <boiskila@gmail.com> Signed-off-by: blalov <boiskila@gmail.com> * fix typo in component name Signed-off-by: Boyko Lalov <boiskila@gmail.com> Signed-off-by: blalov <boiskila@gmail.com> * create query link + ui enhancements Signed-off-by: Boyko Lalov <boiskila@gmail.com> Signed-off-by: blalov <boiskila@gmail.com> * add count to state labels Signed-off-by: blalov <boiskila@gmail.com> * put alerts table render in the right place Signed-off-by: blalov <boiskila@gmail.com> * refactoring Signed-off-by: blalov <boiskila@gmail.com> * fix rules endpoint test Signed-off-by: blalov <boiskila@gmail.com> * lint fixes Signed-off-by: blalov <boiskila@gmail.com> * test query params Signed-off-by: blalov <boiskila@gmail.com> * refactoring Signed-off-by: blalov <boiskila@gmail.com> * review changes Signed-off-by: blalov <boiskila@gmail.com> * adding down arrow as click indicator in Alert Signed-off-by: blalov <boiskila@gmail.com> * add period at the end of the comment Signed-off-by: blalov <boiskila@gmail.com> * review changes Signed-off-by: blalov <boiskila@gmail.com> * remove left-over css Signed-off-by: blalov <boiskila@gmail.com> * adding expand/collapse arrows on Alert Signed-off-by: blalov <boiskila@gmail.com> * create proper expression for alert name Signed-off-by: blalov <boiskila@gmail.com>
2019-12-09 14:42:59 -08:00
import React, { FC, useState, Fragment } from 'react';
import { ButtonGroup, Button, Row, Badge } from 'reactstrap';
import CollapsibleAlertPanel from './CollapsibleAlertPanel';
import Checkbox from '../../Checkbox';
import { isPresent } from '../../utils/func';
export type RuleState = keyof RuleStatus<any>;
export interface Rule {
alerts: Alert[];
annotations: Record<string, string>;
duration: number;
health: string;
labels: Record<string, string>;
name: string;
query: string;
state: RuleState;
type: string;
}
export interface RuleStatus<T> {
firing: T;
pending: T;
inactive: T;
}
export interface AlertsProps {
groups?: RuleGroup[];
statsCount: RuleStatus<number>;
}
interface Alert {
labels: Record<string, string>;
state: RuleState;
value: string;
annotations: Record<string, string>;
activeAt: string;
}
interface RuleGroup {
name: string;
file: string;
rules: Rule[];
interval: number;
}
const AlertsContent: FC<AlertsProps> = ({ groups = [], statsCount }) => {
const [state, setState] = useState<RuleStatus<boolean>>({
firing: true,
pending: true,
inactive: true,
});
const [showAnnotations, setShowAnnotations] = useState(false);
const toggle = (ruleState: RuleState) => () => {
setState({
...state,
[ruleState]: !state[ruleState],
});
};
return (
<>
<ButtonGroup className="mb-3">
<Button active={state.inactive} onClick={toggle('inactive')} color="primary">
Inactive ({statsCount.inactive})
</Button>
<Button active={state.pending} onClick={toggle('pending')} color="primary">
Pending ({statsCount.pending})
</Button>
<Button active={state.firing} onClick={toggle('firing')} color="primary">
Firing ({statsCount.firing})
</Button>
</ButtonGroup>
<Row className="mb-2">
<Checkbox
id="show-annotations"
wrapperStyles={{ margin: '0 0 0 15px', alignSelf: 'center' }}
onClick={() => setShowAnnotations(!showAnnotations)}
>
Show annotations
</Checkbox>
</Row>
{groups.map((group, i) => {
return (
<Fragment key={i}>
<StatusBadges rules={group.rules}>
{group.file} > {group.name}
</StatusBadges>
{group.rules.map((rule, j) => {
return (
state[rule.state] && (
<CollapsibleAlertPanel key={rule.name + j} showAnnotations={showAnnotations} rule={rule} />
)
);
})}
</Fragment>
);
})}
</>
);
};
interface StatusBadgesProps {
rules: Rule[];
}
const StatusBadges: FC<StatusBadgesProps> = ({ rules, children }) => {
const statesCounter = rules.reduce<any>(
(acc, r) => {
return {
...acc,
[r.state]: acc[r.state] + r.alerts.length,
};
},
{
firing: 0,
pending: 0,
}
);
return (
<div className="status-badges border rounded-sm" style={{ lineHeight: 1.1 }}>
{children}
<div className="badges-wrapper">
{isPresent(statesCounter.inactive) && <Badge color="success">inactive</Badge>}
{statesCounter.pending > 0 && <Badge color="warning">pending ({statesCounter.pending})</Badge>}
{statesCounter.firing > 0 && <Badge color="danger">firing ({statesCounter.firing})</Badge>}
</div>
</div>
);
};
AlertsContent.displayName = 'Alerts';
export default AlertsContent;