From b0d6ac5f42c0a082d77fb5fa256ef885e1e828e9 Mon Sep 17 00:00:00 2001 From: Andrej Ocenas Date: Tue, 24 Sep 2019 10:18:34 +0200 Subject: [PATCH] Explore: Refactor live tail controls (#19328) --- .../app/features/explore/ExploreToolbar.tsx | 50 +++++----------- public/app/features/explore/LogsContainer.tsx | 50 ++++++---------- .../features/explore/useLiveTailControls.ts | 57 +++++++++++++++++++ 3 files changed, 86 insertions(+), 71 deletions(-) create mode 100644 public/app/features/explore/useLiveTailControls.ts diff --git a/public/app/features/explore/ExploreToolbar.tsx b/public/app/features/explore/ExploreToolbar.tsx index 81f463adac1..fdfc13e0a97 100644 --- a/public/app/features/explore/ExploreToolbar.tsx +++ b/public/app/features/explore/ExploreToolbar.tsx @@ -14,7 +14,6 @@ import { DataQuery, Tooltip, ButtonSelect, - RefreshPicker, SetInterval, } from '@grafana/ui'; import { RawTimeRange, TimeZone, TimeRange, SelectableValue } from '@grafana/data'; @@ -30,7 +29,6 @@ import { changeMode, clearOrigin, } from './state/actions'; -import { changeRefreshIntervalAction, setPausedStateAction } from './state/actionTypes'; import { updateLocation } from 'app/core/actions'; import { getTimeZone } from '../profile/state/selectors'; import { getDashboardSrv } from '../dashboard/services/DashboardSrv'; @@ -39,6 +37,7 @@ import { ExploreTimeControls } from './ExploreTimeControls'; import { LiveTailButton } from './LiveTailButton'; import { ResponsiveButton } from './ResponsiveButton'; import { RunButton } from './RunButton'; +import { LiveTailControls } from './useLiveTailControls'; const getStyles = memoizeOne(() => { return { @@ -81,8 +80,6 @@ interface DispatchProps { changeMode: typeof changeMode; clearOrigin: typeof clearOrigin; updateLocation: typeof updateLocation; - changeRefreshIntervalAction: typeof changeRefreshIntervalAction; - setPausedStateAction: typeof setPausedStateAction; } type Props = StateProps & DispatchProps & OwnProps; @@ -139,29 +136,6 @@ export class UnConnectedExploreToolbar extends PureComponent { }); }; - stopLive = () => { - const { exploreId } = this.props; - this.pauseLive(); - // TODO referencing this from perspective of refresh picker when there is designated button for it now is not - // great. Needs another refactor. - this.props.changeRefreshIntervalAction({ exploreId, refreshInterval: RefreshPicker.offOption.value }); - }; - - startLive = () => { - const { exploreId } = this.props; - this.props.changeRefreshIntervalAction({ exploreId, refreshInterval: RefreshPicker.liveOption.value }); - }; - - pauseLive = () => { - const { exploreId } = this.props; - this.props.setPausedStateAction({ exploreId, isPaused: true }); - }; - - resumeLive = () => { - const { exploreId } = this.props; - this.props.setPausedStateAction({ exploreId, isPaused: false }); - }; - render() { const { datasourceMissing, @@ -305,14 +279,18 @@ export class UnConnectedExploreToolbar extends PureComponent { {hasLiveOption && (
- + + {controls => ( + + )} +
)} @@ -411,8 +389,6 @@ const mapDispatchToProps: DispatchProps = { split: splitOpen, changeMode: changeMode, clearOrigin, - changeRefreshIntervalAction, - setPausedStateAction, }; export const ExploreToolbar = hot(module)( diff --git a/public/app/features/explore/LogsContainer.tsx b/public/app/features/explore/LogsContainer.tsx index 4893b5d156c..2e70c5e8e15 100644 --- a/public/app/features/explore/LogsContainer.tsx +++ b/public/app/features/explore/LogsContainer.tsx @@ -1,7 +1,7 @@ import React, { PureComponent } from 'react'; import { hot } from 'react-hot-loader'; import { connect } from 'react-redux'; -import { DataSourceApi, Collapse, RefreshPicker } from '@grafana/ui'; +import { DataSourceApi, Collapse } from '@grafana/ui'; import { RawTimeRange, @@ -18,16 +18,13 @@ import { ExploreId, ExploreItemState } from 'app/types/explore'; import { StoreState } from 'app/types'; import { changeDedupStrategy, updateTimeRange } from './state/actions'; -import { - toggleLogLevelAction, - changeRefreshIntervalAction, - setPausedStateAction, -} from 'app/features/explore/state/actionTypes'; +import { toggleLogLevelAction } from 'app/features/explore/state/actionTypes'; import { deduplicatedLogsSelector, exploreItemUIStateSelector } from 'app/features/explore/state/selectors'; import { getTimeZone } from '../profile/state/selectors'; import { LiveLogsWithTheme } from './LiveLogs'; import { Logs } from './Logs'; import { LogsCrossFadeTransition } from './utils/LogsCrossFadeTransition'; +import { LiveTailControls } from './useLiveTailControls'; interface LogsContainerProps { datasourceInstance: DataSourceApi | null; @@ -48,11 +45,9 @@ interface LogsContainerProps { dedupStrategy: LogsDedupStrategy; width: number; isLive: boolean; - stopLive: typeof changeRefreshIntervalAction; updateTimeRange: typeof updateTimeRange; range: TimeRange; absoluteRange: AbsoluteTimeRange; - setPausedStateAction: typeof setPausedStateAction; isPaused: boolean; } @@ -63,22 +58,6 @@ export class LogsContainer extends PureComponent { updateTimeRange({ exploreId, absoluteRange }); }; - onStopLive = () => { - const { exploreId } = this.props; - this.onPause(); - this.props.stopLive({ exploreId, refreshInterval: RefreshPicker.offOption.value }); - }; - - onPause = () => { - const { exploreId } = this.props; - this.props.setPausedStateAction({ exploreId, isPaused: true }); - }; - - onResume = () => { - const { exploreId } = this.props; - this.props.setPausedStateAction({ exploreId, isPaused: false }); - }; - handleDedupStrategyChange = (dedupStrategy: LogsDedupStrategy) => { this.props.changeDedupStrategy(this.props.exploreId, dedupStrategy); }; @@ -116,20 +95,25 @@ export class LogsContainer extends PureComponent { range, width, isLive, + exploreId, } = this.props; return ( <> - + + {controls => ( + + )} + @@ -198,9 +182,7 @@ function mapStateToProps(state: StoreState, { exploreId }: { exploreId: string } const mapDispatchToProps = { changeDedupStrategy, toggleLogLevelAction, - stopLive: changeRefreshIntervalAction, updateTimeRange, - setPausedStateAction, }; export default hot(module)( diff --git a/public/app/features/explore/useLiveTailControls.ts b/public/app/features/explore/useLiveTailControls.ts new file mode 100644 index 00000000000..8db44f107c7 --- /dev/null +++ b/public/app/features/explore/useLiveTailControls.ts @@ -0,0 +1,57 @@ +import React, { useCallback } from 'react'; +import { useDispatch } from 'react-redux'; + +import { changeRefreshInterval } from './state/actions'; +import { setPausedStateAction } from './state/actionTypes'; +import { RefreshPicker } from '@grafana/ui'; +import { ExploreId } from '../../types'; + +/** + * Hook that gives you all the functions needed to control the live tailing. + */ +export function useLiveTailControls(exploreId: ExploreId) { + const dispatch = useDispatch(); + + const pause = useCallback(() => { + dispatch(setPausedStateAction({ exploreId, isPaused: true })); + }, [exploreId, dispatch]); + + const resume = useCallback(() => { + dispatch(setPausedStateAction({ exploreId, isPaused: false })); + }, [exploreId, dispatch]); + + const stop = useCallback(() => { + // We need to pause here first because there is transition where we are not live but live logs are still shown + // to cross fade with the normal view. This will prevent reordering of the logs in the live view during the + // transition. + pause(); + + // TODO referencing this from perspective of refresh picker when there is designated button for it now is not + // great. Needs a bit of refactoring. + dispatch(changeRefreshInterval(exploreId, RefreshPicker.offOption.value)); + }, [exploreId, dispatch, pause]); + + const start = useCallback(() => { + dispatch(changeRefreshInterval(exploreId, RefreshPicker.liveOption.value)); + }, [exploreId, dispatch]); + + return { + pause, + resume, + stop, + start, + }; +} + +type Props = { + exploreId: ExploreId; + children: (controls: ReturnType) => React.ReactElement; +}; + +/** + * If you can't use the hook you can use this as a render prop pattern. + */ +export function LiveTailControls(props: Props) { + const controls = useLiveTailControls(props.exploreId); + return props.children(controls); +}