mirror of https://github.com/grafana/grafana
React: refactor away from unsafe lifecycle methods (#21291)
* refactor aliasBy and PopoverCtrl components * refactor Aggregations component * refactor MetricSelect component * refactor UserProvider * popoverCtr: remove redundant logic * simplified the MetricsSelect a bit. * skipping testing of internal component logic. * changed to componentWillMount. * changed elapsed time to a functional component. * rewrote the tests. * fixed missing test title. * fixed a tiny issue with elapsed time. * rename of field. Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com>pull/24802/head
parent
44fae66bc0
commit
1e74037eae
@ -0,0 +1,48 @@ |
||||
import React from 'react'; |
||||
import { shallow } from 'enzyme'; |
||||
import { MetricSelect } from './MetricSelect'; |
||||
import { LegacyForms } from '@grafana/ui'; |
||||
const { Select } = LegacyForms; |
||||
|
||||
describe('MetricSelect', () => { |
||||
describe('When receive props', () => { |
||||
it('should pass correct set of props to Select component', () => { |
||||
const props: any = { |
||||
placeholder: 'Select Reducer', |
||||
className: 'width-15', |
||||
options: [], |
||||
variables: [], |
||||
}; |
||||
const wrapper = shallow(<MetricSelect {...props} />); |
||||
expect(wrapper.find(Select).props()).toMatchObject({ |
||||
className: 'width-15', |
||||
isMulti: false, |
||||
isClearable: false, |
||||
backspaceRemovesValue: false, |
||||
isSearchable: true, |
||||
maxMenuHeight: 500, |
||||
placeholder: 'Select Reducer', |
||||
}); |
||||
}); |
||||
it('should pass callbacks correctly to the Select component', () => { |
||||
const spyOnChange = jest.fn(); |
||||
const props: any = { |
||||
onChange: spyOnChange, |
||||
options: [], |
||||
variables: [], |
||||
}; |
||||
const wrapper = shallow(<MetricSelect {...props} />); |
||||
wrapper |
||||
.find(Select) |
||||
.props() |
||||
.onChange({ value: 'foo' }); |
||||
expect( |
||||
wrapper |
||||
.find(Select) |
||||
.props() |
||||
.noOptionsMessage() |
||||
).toEqual('No options found'); |
||||
expect(spyOnChange).toHaveBeenCalledWith('foo'); |
||||
}); |
||||
}); |
||||
}); |
@ -1,76 +1,22 @@ |
||||
import React, { PureComponent } from 'react'; |
||||
import { toDuration } from '@grafana/data'; |
||||
import React, { FC, useState, useEffect } from 'react'; |
||||
import { useInterval } from 'react-use'; |
||||
import { Time, TimeProps } from './Time'; |
||||
|
||||
const INTERVAL = 150; |
||||
|
||||
export interface Props { |
||||
time?: number; |
||||
export interface ElapsedTimeProps extends Omit<TimeProps, 'timeInMs'> { |
||||
// Use this to reset the timer. Any value is allowed just need to be !== from the previous.
|
||||
// Keep in mind things like [] !== [] or {} !== {}.
|
||||
resetKey?: any; |
||||
className?: string; |
||||
humanize?: boolean; |
||||
} |
||||
|
||||
export interface State { |
||||
elapsed: number; |
||||
} |
||||
|
||||
/** |
||||
* Shows an incremental time ticker of elapsed time from some event. |
||||
*/ |
||||
export default class ElapsedTime extends PureComponent<Props, State> { |
||||
offset: number; |
||||
timer: number; |
||||
|
||||
state = { |
||||
elapsed: 0, |
||||
}; |
||||
|
||||
start() { |
||||
this.offset = Date.now(); |
||||
this.timer = window.setInterval(this.tick, INTERVAL); |
||||
} |
||||
|
||||
tick = () => { |
||||
const jetzt = Date.now(); |
||||
const elapsed = jetzt - this.offset; |
||||
this.setState({ elapsed }); |
||||
}; |
||||
export const ElapsedTime: FC<ElapsedTimeProps> = ({ resetKey, humanize, className }) => { |
||||
const [elapsed, setElapsed] = useState(0); // the current value of elapsed
|
||||
|
||||
UNSAFE_componentWillReceiveProps(nextProps: Props) { |
||||
if (nextProps.time) { |
||||
clearInterval(this.timer); |
||||
} else if (this.props.time) { |
||||
this.start(); |
||||
} |
||||
// hook that will schedule a interval and then update the elapsed value on every tick.
|
||||
useInterval(() => setElapsed(elapsed + INTERVAL), INTERVAL); |
||||
// this effect will only be run when resetKey changes. This will reset the elapsed to 0.
|
||||
useEffect(() => setElapsed(0), [resetKey]); |
||||
|
||||
if (nextProps.resetKey !== this.props.resetKey) { |
||||
clearInterval(this.timer); |
||||
this.start(); |
||||
} |
||||
} |
||||
|
||||
componentDidMount() { |
||||
this.start(); |
||||
} |
||||
|
||||
componentWillUnmount() { |
||||
clearInterval(this.timer); |
||||
} |
||||
|
||||
render() { |
||||
const { elapsed } = this.state; |
||||
const { className, time, humanize } = this.props; |
||||
const value = (time || elapsed) / 1000; |
||||
let displayValue = `${value.toFixed(1)}s`; |
||||
if (humanize) { |
||||
const duration = toDuration(elapsed); |
||||
const hours = duration.hours(); |
||||
const minutes = duration.minutes(); |
||||
const seconds = duration.seconds(); |
||||
displayValue = hours ? `${hours}h ${minutes}m ${seconds}s` : minutes ? ` ${minutes}m ${seconds}s` : `${seconds}s`; |
||||
} |
||||
return <span className={`elapsed-time ${className}`}>{displayValue}</span>; |
||||
} |
||||
} |
||||
return <Time timeInMs={elapsed} className={className} humanize={humanize} />; |
||||
}; |
||||
|
@ -0,0 +1,35 @@ |
||||
import React, { FC } from 'react'; |
||||
import { toDuration } from '@grafana/data'; |
||||
|
||||
export interface TimeProps { |
||||
timeInMs: number; |
||||
className?: string; |
||||
humanize?: boolean; |
||||
} |
||||
|
||||
export const Time: FC<TimeProps> = ({ timeInMs, className, humanize }) => { |
||||
return <span className={`elapsed-time ${className}`}>{formatTime(timeInMs, humanize)}</span>; |
||||
}; |
||||
|
||||
const formatTime = (timeInMs: number, humanize = false): string => { |
||||
const inSeconds = timeInMs / 1000; |
||||
|
||||
if (!humanize) { |
||||
return `${inSeconds.toFixed(1)}s`; |
||||
} |
||||
|
||||
const duration = toDuration(inSeconds, 'seconds'); |
||||
const hours = duration.hours(); |
||||
const minutes = duration.minutes(); |
||||
const seconds = duration.seconds(); |
||||
|
||||
if (hours) { |
||||
return `${hours}h ${minutes}m ${seconds}s`; |
||||
} |
||||
|
||||
if (minutes) { |
||||
return `${minutes}m ${seconds}s`; |
||||
} |
||||
|
||||
return `${seconds}s`; |
||||
}; |
Loading…
Reference in new issue