1
import React, { Component } from 'react';
2
import { Button, ButtonGroup, Form, Input, InputGroup, InputGroupAddon } from 'reactstrap';
4
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
5
import { faChartArea, faChartLine, faMinus, faPlus, faBarChart } from '@fortawesome/free-solid-svg-icons';
6
import TimeInput from './TimeInput';
7
import { formatDuration, parseDuration } from '../../utils';
8
import { GraphDisplayMode } from './Panel';
10
interface GraphControlsProps {
12
endTime: number | null;
13
useLocalTime: boolean;
14
resolution: number | null;
15
displayMode: GraphDisplayMode;
16
isHeatmapData: boolean;
17
showExemplars: boolean;
18
onChangeRange: (range: number) => void;
19
onChangeEndTime: (endTime: number | null) => void;
20
onChangeResolution: (resolution: number | null) => void;
21
onChangeShowExemplars: (show: boolean) => void;
22
onChangeDisplayMode: (mode: GraphDisplayMode) => void;
25
class GraphControls extends Component<GraphControlsProps> {
26
private rangeRef = React.createRef<HTMLInputElement>();
27
private resolutionRef = React.createRef<HTMLInputElement>();
50
].map((s) => s * 1000);
52
onChangeRangeInput = (rangeText: string): void => {
53
const range = parseDuration(rangeText);
55
this.changeRangeInput(this.props.range);
57
this.props.onChangeRange(range);
61
changeRangeInput = (range: number): void => {
62
if (this.rangeRef.current !== null) {
63
this.rangeRef.current.value = formatDuration(range);
67
increaseRange = (): void => {
68
for (const range of this.rangeSteps) {
69
if (this.props.range < range) {
70
this.changeRangeInput(range);
71
this.props.onChangeRange(range);
77
decreaseRange = (): void => {
78
for (const range of this.rangeSteps.slice().reverse()) {
79
if (this.props.range > range) {
80
this.changeRangeInput(range);
81
this.props.onChangeRange(range);
87
changeResolutionInput = (resolution: number | null): void => {
88
if (this.resolutionRef.current !== null) {
89
this.resolutionRef.current.value = resolution !== null ? resolution.toString() : '';
93
componentDidUpdate(prevProps: GraphControlsProps): void {
94
if (prevProps.range !== this.props.range) {
95
this.changeRangeInput(this.props.range);
97
if (prevProps.resolution !== this.props.resolution) {
98
this.changeResolutionInput(this.props.resolution);
102
render(): JSX.Element {
104
<Form inline className="graph-controls" onSubmit={(e) => e.preventDefault()}>
105
<InputGroup className="range-input" size="sm">
106
<InputGroupAddon addonType="prepend">
107
<Button title="Decrease range" onClick={this.decreaseRange}>
108
<FontAwesomeIcon icon={faMinus} fixedWidth />
113
defaultValue={formatDuration(this.props.range)}
114
innerRef={this.rangeRef}
116
if (this.rangeRef.current) {
117
this.onChangeRangeInput(this.rangeRef.current.value);
120
onKeyDown={(e: React.KeyboardEvent<HTMLInputElement>) =>
121
e.key === 'Enter' && this.rangeRef.current && this.onChangeRangeInput(this.rangeRef.current.value)
125
<InputGroupAddon addonType="append">
126
<Button title="Increase range" onClick={this.increaseRange}>
127
<FontAwesomeIcon icon={faPlus} fixedWidth />
133
time={this.props.endTime}
134
useLocalTime={this.props.useLocalTime}
135
range={this.props.range}
136
placeholder="End time"
137
onChangeTime={this.props.onChangeEndTime}
141
placeholder="Res. (s)"
142
className="resolution-input"
143
defaultValue={this.props.resolution !== null ? this.props.resolution.toString() : ''}
144
innerRef={this.resolutionRef}
146
if (this.resolutionRef.current) {
147
const res = parseInt(this.resolutionRef.current.value);
148
this.props.onChangeResolution(res ? res : null);
154
<ButtonGroup className="stacked-input" size="sm">
156
title="Show unstacked line graph"
157
onClick={() => this.props.onChangeDisplayMode(GraphDisplayMode.Lines)}
158
active={this.props.displayMode === GraphDisplayMode.Lines}
160
<FontAwesomeIcon icon={faChartLine} fixedWidth />
163
title="Show stacked graph"
164
onClick={() => this.props.onChangeDisplayMode(GraphDisplayMode.Stacked)}
165
active={this.props.displayMode === GraphDisplayMode.Stacked}
167
<FontAwesomeIcon icon={faChartArea} fixedWidth />
169
{/* TODO: Consider replacing this button with a select dropdown in the future,
170
to allow users to choose from multiple histogram series if available. */}
171
{this.props.isHeatmapData && (
173
title="Show heatmap graph"
174
onClick={() => this.props.onChangeDisplayMode(GraphDisplayMode.Heatmap)}
175
active={this.props.displayMode === GraphDisplayMode.Heatmap}
177
<FontAwesomeIcon icon={faBarChart} fixedWidth />
182
<ButtonGroup className="show-exemplars" size="sm">
183
{this.props.showExemplars ? (
184
<Button title="Hide exemplars" onClick={() => this.props.onChangeShowExemplars(false)} active={true}>
188
<Button title="Show exemplars" onClick={() => this.props.onChangeShowExemplars(true)} active={false}>
198
export default GraphControls;