import React, { PureComponent } from 'react'; import moment from 'moment'; import * as utils from '../../../datasource-zabbix/utils'; import { MODE_ITEMID, MODE_METRICS } from '../../../datasource-zabbix/constants'; import { ProblemDTO, ZBXHost, ZBXGroup, ZBXEvent, ZBXTag, ZBXAlert } from '../../../datasource-zabbix/types'; import { ZBXItem, ZBXAcknowledge, GFTimeRange, RTRow } from '../../types'; import { AckModal, AckProblemData } from '../AckModal'; import EventTag from '../EventTag'; import Tooltip from '../../../components/Tooltip/Tooltip'; import ProblemStatusBar from './ProblemStatusBar'; import AcknowledgesList from './AcknowledgesList'; import ProblemTimeline from './ProblemTimeline'; import FAIcon from '../FAIcon'; import { renderUrl } from '../../utils'; import { getLocationSrv } from '@grafana/runtime'; interface ProblemDetailsProps extends RTRow { rootWidth: number; timeRange: GFTimeRange; showTimeline?: boolean; panelId?: number; getProblemEvents: (problem: ProblemDTO) => Promise; getProblemAlerts: (problem: ProblemDTO) => Promise; onProblemAck?: (problem: ProblemDTO, data: AckProblemData) => Promise | any; onTagClick?: (tag: ZBXTag, datasource: string, ctrlKey?: boolean, shiftKey?: boolean) => void; } interface ProblemDetailsState { events: ZBXEvent[]; alerts: ZBXAlert[]; show: boolean; showAckDialog: boolean; } export default class ProblemDetails extends PureComponent { constructor(props) { super(props); this.state = { events: [], alerts: [], show: false, showAckDialog: false, }; } componentDidMount() { if (this.props.showTimeline) { this.fetchProblemEvents(); } this.fetchProblemAlerts(); requestAnimationFrame(() => { this.setState({ show: true }); }); } handleTagClick = (tag: ZBXTag, ctrlKey?: boolean, shiftKey?: boolean) => { if (this.props.onTagClick) { this.props.onTagClick(tag, this.props.original.datasource, ctrlKey, shiftKey); } } fetchProblemEvents() { const problem = this.props.original; this.props.getProblemEvents(problem) .then(events => { this.setState({ events }); }); } fetchProblemAlerts() { const problem = this.props.original; this.props.getProblemAlerts(problem) .then(alerts => { this.setState({ alerts }); }); } ackProblem = (data: AckProblemData) => { const problem = this.props.original as ProblemDTO; return this.props.onProblemAck(problem, data).then(result => { this.closeAckDialog(); }); } showAckDialog = () => { this.setState({ showAckDialog: true }); } closeAckDialog = () => { this.setState({ showAckDialog: false }); } openInExplore = () => { const problem = this.props.original as ProblemDTO; let query: any = {}; if (problem.items?.length === 1 && problem.hosts?.length === 1) { const item = problem.items[0]; const host = problem.hosts[0]; query = { queryType: MODE_METRICS, group: { filter: '/.*/' }, application: { filter: '' }, host: { filter: host.name }, item: { filter: item.name }, }; } else { const itemids = problem.items?.map(p => p.itemid).join(','); query = { queryType: MODE_ITEMID, itemids: itemids, }; } const state: any = { datasource: problem.datasource, context: 'explore', originPanelId: this.props.panelId, queries: [query], }; const exploreState = JSON.stringify(state); const url = renderUrl('/explore', { left: exploreState }); getLocationSrv().update({ path: url, query: {} }); }; render() { 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.timestamp).fromNow(true); const showAcknowledges = problem.acknowledges && problem.acknowledges.length !== 0; const problemSeverity = Number(problem.severity); return (
{age}
{problem.items && }
{problem.showAckButton &&
}
{problem.comments &&
Description:  {problem.comments}
} {problem.tags && problem.tags.length > 0 &&
{problem.tags && problem.tags.map(tag => ) }
} {this.props.showTimeline && this.state.events.length > 0 && } {showAcknowledges && !wideLayout &&
Acknowledges
}
{showAcknowledges && wideLayout &&
Acknowledges
}
{problem.datasource}
{problem.proxy &&
{problem.proxy}
} {problem.groups && } {problem.hosts && }
); } } interface ProblemItemProps { item: ZBXItem; showName?: boolean; } function ProblemItem(props: ProblemItemProps) { const { item, showName } = props; const itemName = utils.expandItemName(item.name, item.key_); return (
{showName && {item.name}: } {item.lastvalue}
); } interface ProblemItemsProps { items: ZBXItem[]; } class ProblemItems extends PureComponent { render() { const { items } = this.props; return (items.length > 1 ? items.map(item => ) : ); } } interface ProblemGroupsProps { groups: ZBXGroup[]; className?: string; } class ProblemGroups extends PureComponent { render() { return this.props.groups.map(g => (
{g.name}
)); } } interface ProblemHostsProps { hosts: ZBXHost[]; className?: string; } class ProblemHosts extends PureComponent { render() { return this.props.hosts.map(h => (
{h.name}
)); } } interface ProblemActionButtonProps { icon: string; tooltip?: string; className?: string; onClick?: (event?) => void; } class ProblemActionButton extends PureComponent { handleClick = (event) => { this.props.onClick(event); } render() { const { icon, tooltip, className } = this.props; let button = ( ); if (tooltip) { button = ( {button} ); } return button; } } interface ExploreButtonProps { onClick: (event?) => void; } const ExploreButton: React.FC = ({ onClick }) => { return ( ); };