problems: initial timeline

This commit is contained in:
Alexander Zobnin
2018-12-14 23:30:41 +03:00
parent 1d1559d8e0
commit 566db376a2
5 changed files with 198 additions and 10 deletions

View File

@@ -0,0 +1,105 @@
import React, { PureComponent } from 'react';
import { GFTimeRange, ZBXEvent } from 'panel-triggers/types';
const DEFAULT_OK_COLOR = 'rgb(56, 189, 113)';
const DEFAULT_PROBLEM_COLOR = 'rgb(215, 0, 0)';
const EVENT_ITEM_SIZE = 16;
export interface ProblemTimelineProps {
events: ZBXEvent[];
timeRange: GFTimeRange;
okColor?: string;
problemColor?: string;
}
interface ProblemTimelineState {
width: number;
}
export default class ProblemTimeline extends PureComponent<ProblemTimelineProps, ProblemTimelineState> {
rootWidth: number;
rootRef: any;
static defaultProps = {
okColor: DEFAULT_OK_COLOR,
problemColor: DEFAULT_PROBLEM_COLOR,
};
constructor(props) {
super(props);
this.state = {
width: 0
};
}
setRootRef = ref => {
this.rootRef = ref;
const width = this.rootRef && this.rootRef.clientWidth || 0;
this.setState({ width });
}
render() {
if (!this.rootRef) {
return <div className="event-timeline" ref={this.setRootRef} />;
}
const { events, timeRange } = this.props;
const { timeFrom, timeTo } = timeRange;
const range = timeTo - timeFrom;
const width = this.state.width;
let firstItem;
if (events.length) {
const firstTs = events.length ? Number(events[0].clock) : timeTo;
const duration = (firstTs - timeFrom) / range;
const firstEventColor = events[0].value !== '1' ? this.props.problemColor : this.props.okColor;
const firstEventStyle: React.CSSProperties = {
width: duration * width,
left: 0,
background: firstEventColor,
};
firstItem = (
<div key='0' className="problem-event-interval" style={firstEventStyle}></div>
);
}
const eventsIntervalItems = events.map((event, index) => {
const ts = Number(event.clock);
const nextTs = index < events.length - 1 ? Number(events[index + 1].clock) : timeTo;
const duration = (nextTs - ts) / range;
const posLeft = (ts - timeFrom) / range * width;
const eventColor = event.value === '1' ? this.props.problemColor : this.props.okColor;
const styles: React.CSSProperties = {
width: duration * width,
left: posLeft,
background: eventColor,
};
return (
<div key={event.eventid} className="problem-event-interval" style={styles}></div>
);
});
const eventsItems = events.map(event => {
const ts = Number(event.clock);
const posLeft = (ts - timeFrom) / range * width - EVENT_ITEM_SIZE / 2;
const eventColor = event.value === '1' ? this.props.problemColor : this.props.okColor;
const styles: React.CSSProperties = {
transform: `translate(${posLeft}px, -2px)`,
// background: eventColor,
borderColor: eventColor,
};
return (
<div key={event.eventid} className="problem-event-item" style={styles}></div>
);
});
return (
<div className="event-timeline" ref={this.setRootRef}>
{firstItem}
{eventsIntervalItems}
{eventsItems}
</div>
);
}
}

View File

@@ -1,15 +1,18 @@
import React, { PureComponent } from 'react';
import ReactTable from 'react-table';
import * as utils from '../../datasource-zabbix/utils';
import { ProblemsPanelOptions, Trigger, ZBXItem, ZBXAcknowledge, ZBXHost, ZBXGroup, ZBXEvent, GFTimeRange } from '../types';
import { Modal, AckProblemData } from './Modal';
import EventTag from './EventTag';
import Tooltip from './Tooltip';
import { Modal, AckProblemData } from './Modal';
import { ProblemsPanelOptions, Trigger, ZBXItem, ZBXAcknowledge, ZBXHost, ZBXGroup } from '../types';
import * as utils from '../../datasource-zabbix/utils';
import ProblemTimeline from './ProblemTimeline';
export interface ProblemListProps {
problems: Trigger[];
panelOptions: ProblemsPanelOptions;
loading?: boolean;
timeRange?: GFTimeRange;
getProblemEvents: (ids: string[]) => ZBXEvent[];
}
interface ProblemListState {
@@ -93,7 +96,13 @@ export class ProblemList extends PureComponent<ProblemListProps, ProblemListStat
columns={columns}
defaultPageSize={10}
loading={this.props.loading}
SubComponent={props => <ProblemDetails rootWidth={this.rootWidth} {...props} />}
SubComponent={props =>
<ProblemDetails {...props}
rootWidth={this.rootWidth}
timeRange={this.props.timeRange}
getProblemEvents={this.props.getProblemEvents}
/>
}
expanded={this.getExpandedPage(this.state.page)}
onExpandedChange={this.handleExpandedChange}
onPageChange={page => this.setState({ page })}
@@ -352,6 +361,7 @@ class ProblemActionButton extends PureComponent<ProblemActionButtonProps> {
}
interface ProblemDetailsState {
events: ZBXEvent[];
show: boolean;
showAckDialog: boolean;
}
@@ -360,12 +370,19 @@ class ProblemDetails extends PureComponent<any, ProblemDetailsState> {
constructor(props) {
super(props);
this.state = {
events: [],
show: false,
showAckDialog: false,
};
}
componentDidMount() {
const problem = this.props.original;
this.props.getProblemEvents(problem)
.then(events => {
console.log(events, this.props.timeRange);
this.setState({ events });
});
requestAnimationFrame(() => {
this.setState({ show: true });
});
@@ -417,11 +434,14 @@ class ProblemDetails extends PureComponent<any, ProblemDetailsState> {
<span>{problem.comments}</span>
</div>
}
<div className="problem-tags">
{problem.tags && problem.tags.map(tag =>
<EventTag key={tag.tag + tag.value} tag={tag} highlight={tag.tag === problem.correlation_tag} />)
}
</div>
{problem.tags && problem.tags.length &&
<div className="problem-tags">
{problem.tags && problem.tags.map(tag =>
<EventTag key={tag.tag + tag.value} tag={tag} highlight={tag.tag === problem.correlation_tag} />)
}
</div>
}
<ProblemTimeline events={this.state.events} timeRange={this.props.timeRange} />
{problem.acknowledges && !wideLayout &&
<div className="problem-ack-container">
<h6><FAIcon icon="reply-all" /> Acknowledges</h6>