diff --git a/src/panel-triggers/components/ProblemTimeline.tsx b/src/panel-triggers/components/ProblemTimeline.tsx index cb65193..0ad11ad 100644 --- a/src/panel-triggers/components/ProblemTimeline.tsx +++ b/src/panel-triggers/components/ProblemTimeline.tsx @@ -1,4 +1,5 @@ import React, { PureComponent } from 'react'; +import _ from 'lodash'; import moment from 'moment'; import { GFTimeRange, ZBXEvent } from 'panel-triggers/types'; @@ -21,11 +22,13 @@ export interface ProblemTimelineProps { interface ProblemTimelineState { width: number; highlightedEvent?: ZBXEvent | null; + highlightedRegion?: number | null; showEventInfo?: boolean; } export default class ProblemTimeline extends PureComponent { rootRef: any; + sortedEvents: ZBXEvent[]; static defaultProps = { okColor: DEFAULT_OK_COLOR, @@ -39,16 +42,38 @@ export default class ProblemTimeline extends PureComponent { this.rootRef = ref; const width = ref && ref.clientWidth || 0; this.setState({ width }); } + handlePointHighlight = (event: ZBXEvent, index?: number) => { + const regionToHighlight = this.getRegionToHighlight(index); + this.setState({ + highlightedEvent: event, + showEventInfo: true, + highlightedRegion: regionToHighlight + }); + // this.showEventInfo(event); + } + + handlePointUnHighlight = () => { + this.setState({ showEventInfo: false, highlightedRegion: null }); + } + showEventInfo = (event: ZBXEvent) => { this.setState({ highlightedEvent: event, showEventInfo: true }); } @@ -57,11 +82,16 @@ export default class ProblemTimeline extends PureComponent { + const event = this.sortedEvents[index]; + const regionToHighlight = event.value === '1' ? index + 1 : index; + return regionToHighlight; + } + + sortEvents() { + const events = _.sortBy(this.props.events, e => Number(e.clock)); + this.sortedEvents = events; + return events; } render() { @@ -69,7 +99,8 @@ export default class ProblemTimeline extends PureComponent; } - const { events, timeRange, eventPointSize, eventRegionHeight, problemColor, okColor } = this.props; + const { timeRange, eventPointSize, eventRegionHeight, problemColor, okColor } = this.props; + const events = this.sortEvents(); const boxWidth = this.state.width; const boxHeight = eventPointSize * 2; const width = boxWidth - eventPointSize; @@ -125,6 +156,7 @@ export default class ProblemTimeline extends PureComponent @@ -135,8 +167,8 @@ export default class ProblemTimeline extends PureComponent @@ -191,13 +223,19 @@ interface TimelineRegionsProps { height: number; okColor: string; problemColor: string; + highlightedRegion?: number | null; } class TimelineRegions extends PureComponent { + static defaultProps = { + highlightedRegion: null, + }; + render() { - const { events, timeRange, width, height, okColor, problemColor } = this.props; + const { events, timeRange, width, height, okColor, problemColor, highlightedRegion } = this.props; const { timeFrom, timeTo } = timeRange; const range = timeTo - timeFrom; + console.log(highlightedRegion); let firstItem: React.ReactNode; if (events.length) { @@ -205,6 +243,8 @@ class TimelineRegions extends PureComponent { const duration = (firstTs - timeFrom) / range; const regionWidth = Math.round(duration * width); const firstEventColor = events[0].value !== '1' ? problemColor : okColor; + const highlighted = highlightedRegion === 0; + const className = `problem-event-region ${highlighted ? 'highlighted' : ''}`; const firstEventAttributes = { x: 0, y: 0, @@ -213,7 +253,7 @@ class TimelineRegions extends PureComponent { fill: firstEventColor, }; firstItem = ( - + ); } @@ -224,6 +264,8 @@ class TimelineRegions extends PureComponent { const regionWidth = Math.round(duration * width); const posLeft = Math.round((ts - timeFrom) / range * width); const eventColor = event.value === '1' ? problemColor : okColor; + const highlighted = highlightedRegion && highlightedRegion - 1 === index; + const className = `problem-event-region ${highlighted ? 'highlighted' : ''}`; const attributes = { x: posLeft, y: 0, @@ -233,7 +275,7 @@ class TimelineRegions extends PureComponent { }; return ( - + ); }); @@ -251,46 +293,81 @@ interface TimelinePointsProps { pointSize: number; okColor: string; problemColor: string; - onPointHighlight?: (event: ZBXEvent) => void; + highlightRegion?: boolean; + onPointHighlight?: (event: ZBXEvent, index?: number) => void; onPointUnHighlight?: () => void; } interface TimelinePointsState { order: number[]; - highlighted: number | null; + highlighted: number[]; } class TimelinePoints extends PureComponent { + static defaultProps = { + highlightRegion: true, + }; + constructor(props) { super(props); - this.state = { order: [], highlighted: null }; + this.state = { order: [], highlighted: [] }; } - bringToFront = (index: number, highlight = false ) => { + bringToFront = (indexes: number[], highlight = false) => { const { events } = this.props; - const length = events.length; - const order = events.map((v, i) => i); - order.splice(index, 1); - order.push(index); - const highlighted = highlight ? index : null; + let order = events.map((v, i) => i); + order = moveToEnd(order, indexes); + const highlighted = highlight ? indexes : null; this.setState({ order, highlighted }); } - highlightPoint = index => () => { + highlightPoint = (index: number) => () => { + let pointsToHighlight = [index]; if (this.props.onPointHighlight) { - this.props.onPointHighlight(this.props.events[index]); + if (this.props.highlightRegion) { + pointsToHighlight = this.getRegionEvents(index); + this.props.onPointHighlight(this.props.events[index], index); + } else { + this.props.onPointHighlight(this.props.events[index]); + } } - this.bringToFront(index, true); - // this.setState({ highlighted: this.props.events.length - 1 }); + this.bringToFront(pointsToHighlight, true); } + getRegionEvents(index: number) { + const events = this.props.events; + const event = events[index]; + if (event.value === '1' && index < events.length ) { + // Problem event + for (let i = index; i < events.length; i++) { + if (events[i].value === '0') { + const okEventIndex = i; + return [index, okEventIndex]; + } + } + } else if (event.value === '0' && index > 0) { + // OK event + let lastProblemIndex = null; + for (let i = index - 1; i >= 0; i--) { + if (events[i].value === '1') { + lastProblemIndex = i; + } else { + break; + } + } + if (lastProblemIndex !== null) { + return [index, lastProblemIndex]; + } + } + return [index]; + } unHighlightPoint = index => () => { if (this.props.onPointUnHighlight) { this.props.onPointUnHighlight(); } const order = this.props.events.map((v, i) => i); - this.setState({ order, highlighted: null }); + this.setState({ order, highlighted: [] }); } render() { @@ -298,15 +375,11 @@ class TimelinePoints extends PureComponent { + const eventsItems = events.map((event, i) => { const ts = Number(event.clock); const posLeft = Math.round((ts - timeFrom) / range * width - pointR); const eventColor = event.value === '1' ? problemColor : okColor; - const highlighted = this.state.highlighted === index || ( - this.state.highlighted !== null && index === this.state.highlighted + 1 && event.value !== '1' - ) || ( - this.state.highlighted !== null && index === this.state.highlighted - 1 && event.value === '1' - ); + const highlighted = this.state.highlighted.indexOf(i) !== -1; return ( ); }); @@ -385,3 +458,10 @@ class TimelinePoint extends PureComponent(array: T[], itemsToMove: number[]): T[] { + const removed = _.pullAt(array, itemsToMove); + removed.reverse(); + array.push(...removed); + return array; +} diff --git a/src/sass/_panel-problems.scss b/src/sass/_panel-problems.scss index c1bba6b..b27f1a6 100644 --- a/src/sass/_panel-problems.scss +++ b/src/sass/_panel-problems.scss @@ -165,7 +165,7 @@ transition: all 0.3s ease-out; &.show { - max-height: 16rem; + max-height: 20rem; opacity: 1; } @@ -370,7 +370,8 @@ // transition: all 0.2s ease-out; // opacity: 0.7; - &:hover { + &:hover, + &.highlighted { // opacity: 1; stroke: $zbx-text-highlighted; filter: url(#glowShadow);