Problems: use problems.get method for fetching triggers, closes #495
This commit is contained in:
@@ -3,18 +3,19 @@ import classNames from 'classnames';
|
||||
import _ from 'lodash';
|
||||
import moment from 'moment';
|
||||
import { isNewProblem, formatLastChange } from '../../utils';
|
||||
import { ProblemsPanelOptions, ZBXTrigger, TriggerSeverity, ZBXTag } from '../../types';
|
||||
import { ProblemsPanelOptions, TriggerSeverity } from '../../types';
|
||||
import { AckProblemData, Modal } from '.././Modal';
|
||||
import EventTag from '../EventTag';
|
||||
import Tooltip from '.././Tooltip/Tooltip';
|
||||
import AlertAcknowledges from './AlertAcknowledges';
|
||||
import AlertIcon from './AlertIcon';
|
||||
import { ProblemDTO, ZBXTag } from '../../../datasource-zabbix/types';
|
||||
|
||||
interface AlertCardProps {
|
||||
problem: ZBXTrigger;
|
||||
problem: ProblemDTO;
|
||||
panelOptions: ProblemsPanelOptions;
|
||||
onTagClick?: (tag: ZBXTag, datasource: string, ctrlKey?: boolean, shiftKey?: boolean) => void;
|
||||
onProblemAck?: (problem: ZBXTrigger, data: AckProblemData) => Promise<any> | any;
|
||||
onProblemAck?: (problem: ProblemDTO, data: AckProblemData) => Promise<any> | any;
|
||||
}
|
||||
|
||||
interface AlertCardState {
|
||||
@@ -61,13 +62,13 @@ export default class AlertCard extends PureComponent<AlertCardProps, AlertCardSt
|
||||
const descriptionClass = classNames('alert-rule-item__text', { 'zbx-description--newline': panelOptions.descriptionAtNewLine });
|
||||
|
||||
let severityDesc: TriggerSeverity;
|
||||
severityDesc = _.find(panelOptions.triggerSeverity, s => s.priority === Number(problem.priority));
|
||||
if (problem.lastEvent?.severity) {
|
||||
severityDesc = _.find(panelOptions.triggerSeverity, s => s.priority === Number(problem.lastEvent.severity));
|
||||
severityDesc = _.find(panelOptions.triggerSeverity, s => s.priority === Number(problem.severity));
|
||||
if (problem.severity) {
|
||||
severityDesc = _.find(panelOptions.triggerSeverity, s => s.priority === Number(problem.severity));
|
||||
}
|
||||
|
||||
const lastchange = formatLastChange(problem.lastchangeUnix, panelOptions.customLastChangeFormat && panelOptions.lastChangeFormat);
|
||||
const age = moment.unix(problem.lastchangeUnix).fromNow(true);
|
||||
const lastchange = formatLastChange(problem.timestamp, panelOptions.customLastChangeFormat && panelOptions.lastChangeFormat);
|
||||
const age = moment.unix(problem.timestamp).fromNow(true);
|
||||
|
||||
let newProblem = false;
|
||||
if (panelOptions.highlightNewerThan) {
|
||||
@@ -78,7 +79,7 @@ export default class AlertCard extends PureComponent<AlertCardProps, AlertCardSt
|
||||
let problemColor: string;
|
||||
if (problem.value === '0') {
|
||||
problemColor = panelOptions.okEventColor;
|
||||
} else if (panelOptions.markAckEvents && problem.lastEvent?.acknowledged === "1") {
|
||||
} else if (panelOptions.markAckEvents && problem.acknowledged === "1") {
|
||||
problemColor = panelOptions.ackEventColor;
|
||||
} else {
|
||||
problemColor = severityDesc.color;
|
||||
@@ -159,7 +160,7 @@ export default class AlertCard extends PureComponent<AlertCardProps, AlertCardSt
|
||||
<span><i className="fa fa-question-circle"></i></span>
|
||||
</Tooltip>
|
||||
)}
|
||||
{problem.lastEvent && (
|
||||
{problem.eventid && (
|
||||
<AlertAcknowledgesButton problem={problem} onClick={this.showAckDialog} />
|
||||
)}
|
||||
</div>
|
||||
@@ -174,7 +175,7 @@ export default class AlertCard extends PureComponent<AlertCardProps, AlertCardSt
|
||||
}
|
||||
|
||||
interface AlertHostProps {
|
||||
problem: ZBXTrigger;
|
||||
problem: ProblemDTO;
|
||||
panelOptions: ProblemsPanelOptions;
|
||||
}
|
||||
|
||||
@@ -200,7 +201,7 @@ function AlertHost(props: AlertHostProps) {
|
||||
}
|
||||
|
||||
interface AlertGroupProps {
|
||||
problem: ZBXTrigger;
|
||||
problem: ProblemDTO;
|
||||
panelOptions: ProblemsPanelOptions;
|
||||
}
|
||||
|
||||
@@ -253,7 +254,7 @@ function AlertSeverity(props) {
|
||||
}
|
||||
|
||||
interface AlertAcknowledgesButtonProps {
|
||||
problem: ZBXTrigger;
|
||||
problem: ProblemDTO;
|
||||
onClick: (event?) => void;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,23 +1,24 @@
|
||||
import React, { PureComponent, CSSProperties } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { ProblemsPanelOptions, ZBXTrigger, GFTimeRange, ZBXTag } from '../../types';
|
||||
import { ProblemsPanelOptions, GFTimeRange } from '../../types';
|
||||
import { AckProblemData } from '.././Modal';
|
||||
import AlertCard from './AlertCard';
|
||||
import { ProblemDTO, ZBXTag } from '../../../datasource-zabbix/types';
|
||||
|
||||
export interface AlertListProps {
|
||||
problems: ZBXTrigger[];
|
||||
problems: ProblemDTO[];
|
||||
panelOptions: ProblemsPanelOptions;
|
||||
loading?: boolean;
|
||||
timeRange?: GFTimeRange;
|
||||
pageSize?: number;
|
||||
fontSize?: number;
|
||||
onProblemAck?: (problem: ZBXTrigger, data: AckProblemData) => void;
|
||||
onProblemAck?: (problem: ProblemDTO, data: AckProblemData) => void;
|
||||
onTagClick?: (tag: ZBXTag, datasource: string, ctrlKey?: boolean, shiftKey?: boolean) => void;
|
||||
}
|
||||
|
||||
interface AlertListState {
|
||||
page: number;
|
||||
currentProblems: ZBXTrigger[];
|
||||
currentProblems: ProblemDTO[];
|
||||
}
|
||||
|
||||
export default class AlertList extends PureComponent<AlertListProps, AlertListState> {
|
||||
@@ -51,7 +52,7 @@ export default class AlertList extends PureComponent<AlertListProps, AlertListSt
|
||||
}
|
||||
}
|
||||
|
||||
handleProblemAck = (problem: ZBXTrigger, data: AckProblemData) => {
|
||||
handleProblemAck = (problem: ProblemDTO, data: AckProblemData) => {
|
||||
return this.props.onProblemAck(problem, data);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import moment from 'moment';
|
||||
import * as utils from '../../../datasource-zabbix/utils';
|
||||
import { ZBXTrigger, ZBXItem, ZBXAcknowledge, ZBXHost, ZBXGroup, ZBXEvent, GFTimeRange, RTRow, ZBXTag, ZBXAlert } from '../../types';
|
||||
import { ZBXItem, ZBXAcknowledge, GFTimeRange, RTRow } from '../../types';
|
||||
import { Modal, AckProblemData } from '../Modal';
|
||||
import EventTag from '../EventTag';
|
||||
import Tooltip from '../Tooltip/Tooltip';
|
||||
@@ -9,14 +9,15 @@ import ProblemStatusBar from './ProblemStatusBar';
|
||||
import AcknowledgesList from './AcknowledgesList';
|
||||
import ProblemTimeline from './ProblemTimeline';
|
||||
import FAIcon from '../FAIcon';
|
||||
import { ProblemDTO, ZBXHost, ZBXGroup, ZBXEvent, ZBXTag, ZBXAlert } from '../../../datasource-zabbix/types';
|
||||
|
||||
interface ProblemDetailsProps extends RTRow<ZBXTrigger> {
|
||||
interface ProblemDetailsProps extends RTRow<ProblemDTO> {
|
||||
rootWidth: number;
|
||||
timeRange: GFTimeRange;
|
||||
showTimeline?: boolean;
|
||||
getProblemEvents: (problem: ZBXTrigger) => Promise<ZBXEvent[]>;
|
||||
getProblemAlerts: (problem: ZBXTrigger) => Promise<ZBXAlert[]>;
|
||||
onProblemAck?: (problem: ZBXTrigger, data: AckProblemData) => Promise<any> | any;
|
||||
getProblemEvents: (problem: ProblemDTO) => Promise<ZBXEvent[]>;
|
||||
getProblemAlerts: (problem: ProblemDTO) => Promise<ZBXAlert[]>;
|
||||
onProblemAck?: (problem: ProblemDTO, data: AckProblemData) => Promise<any> | any;
|
||||
onTagClick?: (tag: ZBXTag, datasource: string, ctrlKey?: boolean, shiftKey?: boolean) => void;
|
||||
}
|
||||
|
||||
@@ -71,7 +72,7 @@ export default class ProblemDetails extends PureComponent<ProblemDetailsProps, P
|
||||
}
|
||||
|
||||
ackProblem = (data: AckProblemData) => {
|
||||
const problem = this.props.original as ZBXTrigger;
|
||||
const problem = this.props.original as ProblemDTO;
|
||||
return this.props.onProblemAck(problem, data).then(result => {
|
||||
this.closeAckDialog();
|
||||
}).catch(err => {
|
||||
@@ -89,13 +90,13 @@ export default class ProblemDetails extends PureComponent<ProblemDetailsProps, P
|
||||
}
|
||||
|
||||
render() {
|
||||
const problem = this.props.original as ZBXTrigger;
|
||||
const problem = this.props.original as ProblemDTO;
|
||||
const alerts = this.state.alerts;
|
||||
const rootWidth = this.props.rootWidth;
|
||||
const displayClass = this.state.show ? 'show' : '';
|
||||
const wideLayout = rootWidth > 1200;
|
||||
const compactStatusBar = rootWidth < 800 || problem.acknowledges && wideLayout && rootWidth < 1400;
|
||||
const age = moment.unix(problem.lastchangeUnix).fromNow(true);
|
||||
const age = moment.unix(problem.timestamp).fromNow(true);
|
||||
const showAcknowledges = problem.acknowledges && problem.acknowledges.length !== 0;
|
||||
|
||||
return (
|
||||
|
||||
@@ -5,22 +5,23 @@ import _ from 'lodash';
|
||||
import moment from 'moment';
|
||||
import * as utils from '../../../datasource-zabbix/utils';
|
||||
import { isNewProblem } from '../../utils';
|
||||
import { ProblemsPanelOptions, ZBXTrigger, ZBXEvent, GFTimeRange, RTCell, ZBXTag, TriggerSeverity, RTResized, ZBXAlert } from '../../types';
|
||||
import EventTag from '../EventTag';
|
||||
import ProblemDetails from './ProblemDetails';
|
||||
import { AckProblemData } from '../Modal';
|
||||
import GFHeartIcon from '../GFHeartIcon';
|
||||
import { ProblemsPanelOptions, GFTimeRange, RTCell, TriggerSeverity, RTResized } from '../../types';
|
||||
import { ProblemDTO, ZBXEvent, ZBXTag, ZBXAlert } from '../../../datasource-zabbix/types';
|
||||
|
||||
export interface ProblemListProps {
|
||||
problems: ZBXTrigger[];
|
||||
problems: ProblemDTO[];
|
||||
panelOptions: ProblemsPanelOptions;
|
||||
loading?: boolean;
|
||||
timeRange?: GFTimeRange;
|
||||
pageSize?: number;
|
||||
fontSize?: number;
|
||||
getProblemEvents: (problem: ZBXTrigger) => Promise<ZBXEvent[]>;
|
||||
getProblemAlerts: (problem: ZBXTrigger) => Promise<ZBXAlert[]>;
|
||||
onProblemAck?: (problem: ZBXTrigger, data: AckProblemData) => void;
|
||||
getProblemEvents: (problem: ProblemDTO) => Promise<ZBXEvent[]>;
|
||||
getProblemAlerts: (problem: ProblemDTO) => Promise<ZBXAlert[]>;
|
||||
onProblemAck?: (problem: ProblemDTO, data: AckProblemData) => void;
|
||||
onTagClick?: (tag: ZBXTag, datasource: string, ctrlKey?: boolean, shiftKey?: boolean) => void;
|
||||
onPageSizeChange?: (pageSize: number, pageIndex: number) => void;
|
||||
onColumnResize?: (newResized: RTResized) => void;
|
||||
@@ -47,7 +48,7 @@ export default class ProblemList extends PureComponent<ProblemListProps, Problem
|
||||
this.rootRef = ref;
|
||||
}
|
||||
|
||||
handleProblemAck = (problem: ZBXTrigger, data: AckProblemData) => {
|
||||
handleProblemAck = (problem: ProblemDTO, data: AckProblemData) => {
|
||||
return this.props.onProblemAck(problem, data);
|
||||
}
|
||||
|
||||
@@ -177,20 +178,21 @@ export default class ProblemList extends PureComponent<ProblemListProps, Problem
|
||||
}
|
||||
}
|
||||
|
||||
function SeverityCell(props: RTCell<ZBXTrigger>, problemSeverityDesc: TriggerSeverity[], markAckEvents?: boolean, ackEventColor?: string) {
|
||||
function SeverityCell(props: RTCell<ProblemDTO>, problemSeverityDesc: TriggerSeverity[], markAckEvents?: boolean, ackEventColor?: string) {
|
||||
const problem = props.original;
|
||||
let color: string;
|
||||
|
||||
let severityDesc: TriggerSeverity;
|
||||
severityDesc = _.find(problemSeverityDesc, s => s.priority === Number(problem.priority));
|
||||
if (problem.lastEvent?.severity && problem.value === '1') {
|
||||
severityDesc = _.find(problemSeverityDesc, s => s.priority === Number(problem.lastEvent.severity));
|
||||
const severity = Number(problem.severity);
|
||||
severityDesc = _.find(problemSeverityDesc, s => s.priority === severity);
|
||||
if (problem.severity && problem.value === '1') {
|
||||
severityDesc = _.find(problemSeverityDesc, s => s.priority === severity);
|
||||
}
|
||||
|
||||
color = severityDesc.color;
|
||||
|
||||
// Mark acknowledged triggers with different color
|
||||
if (markAckEvents && problem.lastEvent?.acknowledged === "1") {
|
||||
if (markAckEvents && problem.acknowledged === "1") {
|
||||
color = ackEventColor;
|
||||
}
|
||||
|
||||
@@ -204,7 +206,7 @@ function SeverityCell(props: RTCell<ZBXTrigger>, problemSeverityDesc: TriggerSev
|
||||
const DEFAULT_OK_COLOR = 'rgb(56, 189, 113)';
|
||||
const DEFAULT_PROBLEM_COLOR = 'rgb(215, 0, 0)';
|
||||
|
||||
function StatusCell(props: RTCell<ZBXTrigger>, okColor = DEFAULT_OK_COLOR, problemColor = DEFAULT_PROBLEM_COLOR, highlightNewerThan?: string) {
|
||||
function StatusCell(props: RTCell<ProblemDTO>, okColor = DEFAULT_OK_COLOR, problemColor = DEFAULT_PROBLEM_COLOR, highlightNewerThan?: string) {
|
||||
const status = props.value === '0' ? 'RESOLVED' : 'PROBLEM';
|
||||
const color = props.value === '0' ? okColor : problemColor;
|
||||
let newProblem = false;
|
||||
@@ -216,7 +218,7 @@ function StatusCell(props: RTCell<ZBXTrigger>, okColor = DEFAULT_OK_COLOR, probl
|
||||
);
|
||||
}
|
||||
|
||||
function StatusIconCell(props: RTCell<ZBXTrigger>, highlightNewerThan?: string) {
|
||||
function StatusIconCell(props: RTCell<ProblemDTO>, highlightNewerThan?: string) {
|
||||
const status = props.value === '0' ? 'ok' : 'problem';
|
||||
let newProblem = false;
|
||||
if (highlightNewerThan) {
|
||||
@@ -230,7 +232,7 @@ function StatusIconCell(props: RTCell<ZBXTrigger>, highlightNewerThan?: string)
|
||||
return <GFHeartIcon status={status} className={className} />;
|
||||
}
|
||||
|
||||
function GroupCell(props: RTCell<ZBXTrigger>) {
|
||||
function GroupCell(props: RTCell<ProblemDTO>) {
|
||||
let groups = "";
|
||||
if (props.value && props.value.length) {
|
||||
groups = props.value.map(g => g.name).join(', ');
|
||||
@@ -240,7 +242,7 @@ function GroupCell(props: RTCell<ZBXTrigger>) {
|
||||
);
|
||||
}
|
||||
|
||||
function ProblemCell(props: RTCell<ZBXTrigger>) {
|
||||
function ProblemCell(props: RTCell<ProblemDTO>) {
|
||||
const comments = props.original.comments;
|
||||
return (
|
||||
<div>
|
||||
@@ -250,23 +252,23 @@ function ProblemCell(props: RTCell<ZBXTrigger>) {
|
||||
);
|
||||
}
|
||||
|
||||
function AgeCell(props: RTCell<ZBXTrigger>) {
|
||||
function AgeCell(props: RTCell<ProblemDTO>) {
|
||||
const problem = props.original;
|
||||
const timestamp = moment.unix(problem.lastchangeUnix);
|
||||
const timestamp = moment.unix(problem.timestamp);
|
||||
const age = timestamp.fromNow(true);
|
||||
return <span>{age}</span>;
|
||||
}
|
||||
|
||||
function LastChangeCell(props: RTCell<ZBXTrigger>, customFormat?: string) {
|
||||
function LastChangeCell(props: RTCell<ProblemDTO>, customFormat?: string) {
|
||||
const DEFAULT_TIME_FORMAT = "DD MMM YYYY HH:mm:ss";
|
||||
const problem = props.original;
|
||||
const timestamp = moment.unix(problem.lastchangeUnix);
|
||||
const timestamp = moment.unix(problem.timestamp);
|
||||
const format = customFormat || DEFAULT_TIME_FORMAT;
|
||||
const lastchange = timestamp.format(format);
|
||||
return <span>{lastchange}</span>;
|
||||
}
|
||||
|
||||
interface TagCellProps extends RTCell<ZBXTrigger> {
|
||||
interface TagCellProps extends RTCell<ProblemDTO> {
|
||||
onTagClick: (tag: ZBXTag, datasource: string, ctrlKey?: boolean, shiftKey?: boolean) => void;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import { triggerPanelOptionsTab } from './options_tab';
|
||||
import { migratePanelSchema, CURRENT_SCHEMA_VERSION } from './migrations';
|
||||
import ProblemList from './components/Problems/Problems';
|
||||
import AlertList from './components/AlertList/AlertList';
|
||||
import { ProblemDTO } from 'datasource-zabbix/types';
|
||||
|
||||
const PROBLEM_EVENTS_LIMIT = 100;
|
||||
|
||||
@@ -174,7 +175,7 @@ export class TriggerPanelCtrl extends MetricsPanelCtrl {
|
||||
let triggers = _.cloneDeep(problems);
|
||||
|
||||
triggers = _.map(triggers, this.formatTrigger.bind(this));
|
||||
triggers = this.filterTriggersPost(triggers);
|
||||
triggers = this.filterProblems(triggers);
|
||||
triggers = this.sortTriggers(triggers);
|
||||
|
||||
this.renderData = triggers;
|
||||
@@ -184,30 +185,30 @@ export class TriggerPanelCtrl extends MetricsPanelCtrl {
|
||||
});
|
||||
}
|
||||
|
||||
filterTriggersPost(triggers) {
|
||||
let triggerList = _.cloneDeep(triggers);
|
||||
filterProblems(problems) {
|
||||
let problemsList = _.cloneDeep(problems);
|
||||
|
||||
// Filter acknowledged triggers
|
||||
if (this.panel.showTriggers === 'unacknowledged') {
|
||||
triggerList = _.filter(triggerList, trigger => {
|
||||
problemsList = _.filter(problemsList, trigger => {
|
||||
return !(trigger.acknowledges && trigger.acknowledges.length);
|
||||
});
|
||||
} else if (this.panel.showTriggers === 'acknowledged') {
|
||||
triggerList = _.filter(triggerList, trigger => {
|
||||
problemsList = _.filter(problemsList, trigger => {
|
||||
return trigger.acknowledges && trigger.acknowledges.length;
|
||||
});
|
||||
}
|
||||
|
||||
// Filter triggers by severity
|
||||
triggerList = _.filter(triggerList, trigger => {
|
||||
if (trigger.lastEvent && trigger.lastEvent.severity) {
|
||||
return this.panel.triggerSeverity[trigger.lastEvent.severity].show;
|
||||
problemsList = _.filter(problemsList, problem => {
|
||||
if (problem.severity) {
|
||||
return this.panel.triggerSeverity[problem.severity].show;
|
||||
} else {
|
||||
return this.panel.triggerSeverity[trigger.priority].show;
|
||||
return this.panel.triggerSeverity[problem.priority].show;
|
||||
}
|
||||
});
|
||||
|
||||
return triggerList;
|
||||
return problemsList;
|
||||
}
|
||||
|
||||
sortTriggers(triggerList) {
|
||||
@@ -303,11 +304,11 @@ export class TriggerPanelCtrl extends MetricsPanelCtrl {
|
||||
});
|
||||
}
|
||||
|
||||
getProblemAlerts(problem) {
|
||||
if (!problem.lastEvent || problem.lastEvent.length === 0) {
|
||||
getProblemAlerts(problem: ProblemDTO) {
|
||||
if (!problem.eventid) {
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
const eventids = [problem.lastEvent.eventid];
|
||||
const eventids = [problem.eventid];
|
||||
return getDataSourceSrv().get(problem.datasource)
|
||||
.then((datasource: any) => {
|
||||
return datasource.zabbix.getEventAlerts(eventids);
|
||||
@@ -327,11 +328,11 @@ export class TriggerPanelCtrl extends MetricsPanelCtrl {
|
||||
this.render();
|
||||
}
|
||||
|
||||
acknowledgeTrigger(trigger, message) {
|
||||
const eventid = trigger.lastEvent ? trigger.lastEvent.eventid : null;
|
||||
acknowledgeProblem(problem: ProblemDTO, message) {
|
||||
const eventid = problem.eventid;
|
||||
const grafana_user = this.contextSrv.user.name;
|
||||
const ack_message = grafana_user + ' (Grafana): ' + message;
|
||||
return getDataSourceSrv().get(trigger.datasource)
|
||||
return getDataSourceSrv().get(problem.datasource)
|
||||
.then((datasource: any) => {
|
||||
const userIsEditor = this.contextSrv.isEditor || this.contextSrv.isGrafanaAdmin;
|
||||
if (datasource.disableReadOnlyUsersAck && !userIsEditor) {
|
||||
@@ -399,7 +400,7 @@ export class TriggerPanelCtrl extends MetricsPanelCtrl {
|
||||
onColumnResize: ctrl.handleColumnResize.bind(ctrl),
|
||||
onProblemAck: (trigger, data) => {
|
||||
const message = data.message;
|
||||
return ctrl.acknowledgeTrigger(trigger, message);
|
||||
return ctrl.acknowledgeProblem(trigger, message);
|
||||
},
|
||||
onTagClick: (tag, datasource, ctrlKey, shiftKey) => {
|
||||
if (ctrlKey || shiftKey) {
|
||||
|
||||
Reference in New Issue
Block a user