Commit b0d6ac5f by Andrej Ocenas Committed by GitHub

Explore: Refactor live tail controls (#19328)

parent 22c64018
...@@ -14,7 +14,6 @@ import { ...@@ -14,7 +14,6 @@ import {
DataQuery, DataQuery,
Tooltip, Tooltip,
ButtonSelect, ButtonSelect,
RefreshPicker,
SetInterval, SetInterval,
} from '@grafana/ui'; } from '@grafana/ui';
import { RawTimeRange, TimeZone, TimeRange, SelectableValue } from '@grafana/data'; import { RawTimeRange, TimeZone, TimeRange, SelectableValue } from '@grafana/data';
...@@ -30,7 +29,6 @@ import { ...@@ -30,7 +29,6 @@ import {
changeMode, changeMode,
clearOrigin, clearOrigin,
} from './state/actions'; } from './state/actions';
import { changeRefreshIntervalAction, setPausedStateAction } from './state/actionTypes';
import { updateLocation } from 'app/core/actions'; import { updateLocation } from 'app/core/actions';
import { getTimeZone } from '../profile/state/selectors'; import { getTimeZone } from '../profile/state/selectors';
import { getDashboardSrv } from '../dashboard/services/DashboardSrv'; import { getDashboardSrv } from '../dashboard/services/DashboardSrv';
...@@ -39,6 +37,7 @@ import { ExploreTimeControls } from './ExploreTimeControls'; ...@@ -39,6 +37,7 @@ import { ExploreTimeControls } from './ExploreTimeControls';
import { LiveTailButton } from './LiveTailButton'; import { LiveTailButton } from './LiveTailButton';
import { ResponsiveButton } from './ResponsiveButton'; import { ResponsiveButton } from './ResponsiveButton';
import { RunButton } from './RunButton'; import { RunButton } from './RunButton';
import { LiveTailControls } from './useLiveTailControls';
const getStyles = memoizeOne(() => { const getStyles = memoizeOne(() => {
return { return {
...@@ -81,8 +80,6 @@ interface DispatchProps { ...@@ -81,8 +80,6 @@ interface DispatchProps {
changeMode: typeof changeMode; changeMode: typeof changeMode;
clearOrigin: typeof clearOrigin; clearOrigin: typeof clearOrigin;
updateLocation: typeof updateLocation; updateLocation: typeof updateLocation;
changeRefreshIntervalAction: typeof changeRefreshIntervalAction;
setPausedStateAction: typeof setPausedStateAction;
} }
type Props = StateProps & DispatchProps & OwnProps; type Props = StateProps & DispatchProps & OwnProps;
...@@ -139,29 +136,6 @@ export class UnConnectedExploreToolbar extends PureComponent<Props, {}> { ...@@ -139,29 +136,6 @@ export class UnConnectedExploreToolbar extends PureComponent<Props, {}> {
}); });
}; };
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() { render() {
const { const {
datasourceMissing, datasourceMissing,
...@@ -305,14 +279,18 @@ export class UnConnectedExploreToolbar extends PureComponent<Props, {}> { ...@@ -305,14 +279,18 @@ export class UnConnectedExploreToolbar extends PureComponent<Props, {}> {
{hasLiveOption && ( {hasLiveOption && (
<div className={`explore-toolbar-content-item ${styles.liveTailButtons}`}> <div className={`explore-toolbar-content-item ${styles.liveTailButtons}`}>
<LiveTailButton <LiveTailControls exploreId={exploreId}>
isLive={isLive} {controls => (
isPaused={isPaused} <LiveTailButton
start={this.startLive} isLive={isLive}
pause={this.pauseLive} isPaused={isPaused}
resume={this.resumeLive} start={controls.start}
stop={this.stopLive} pause={controls.pause}
/> resume={controls.resume}
stop={controls.stop}
/>
)}
</LiveTailControls>
</div> </div>
)} )}
</div> </div>
...@@ -411,8 +389,6 @@ const mapDispatchToProps: DispatchProps = { ...@@ -411,8 +389,6 @@ const mapDispatchToProps: DispatchProps = {
split: splitOpen, split: splitOpen,
changeMode: changeMode, changeMode: changeMode,
clearOrigin, clearOrigin,
changeRefreshIntervalAction,
setPausedStateAction,
}; };
export const ExploreToolbar = hot(module)( export const ExploreToolbar = hot(module)(
......
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { hot } from 'react-hot-loader'; import { hot } from 'react-hot-loader';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { DataSourceApi, Collapse, RefreshPicker } from '@grafana/ui'; import { DataSourceApi, Collapse } from '@grafana/ui';
import { import {
RawTimeRange, RawTimeRange,
...@@ -18,16 +18,13 @@ import { ExploreId, ExploreItemState } from 'app/types/explore'; ...@@ -18,16 +18,13 @@ import { ExploreId, ExploreItemState } from 'app/types/explore';
import { StoreState } from 'app/types'; import { StoreState } from 'app/types';
import { changeDedupStrategy, updateTimeRange } from './state/actions'; import { changeDedupStrategy, updateTimeRange } from './state/actions';
import { import { toggleLogLevelAction } from 'app/features/explore/state/actionTypes';
toggleLogLevelAction,
changeRefreshIntervalAction,
setPausedStateAction,
} from 'app/features/explore/state/actionTypes';
import { deduplicatedLogsSelector, exploreItemUIStateSelector } from 'app/features/explore/state/selectors'; import { deduplicatedLogsSelector, exploreItemUIStateSelector } from 'app/features/explore/state/selectors';
import { getTimeZone } from '../profile/state/selectors'; import { getTimeZone } from '../profile/state/selectors';
import { LiveLogsWithTheme } from './LiveLogs'; import { LiveLogsWithTheme } from './LiveLogs';
import { Logs } from './Logs'; import { Logs } from './Logs';
import { LogsCrossFadeTransition } from './utils/LogsCrossFadeTransition'; import { LogsCrossFadeTransition } from './utils/LogsCrossFadeTransition';
import { LiveTailControls } from './useLiveTailControls';
interface LogsContainerProps { interface LogsContainerProps {
datasourceInstance: DataSourceApi | null; datasourceInstance: DataSourceApi | null;
...@@ -48,11 +45,9 @@ interface LogsContainerProps { ...@@ -48,11 +45,9 @@ interface LogsContainerProps {
dedupStrategy: LogsDedupStrategy; dedupStrategy: LogsDedupStrategy;
width: number; width: number;
isLive: boolean; isLive: boolean;
stopLive: typeof changeRefreshIntervalAction;
updateTimeRange: typeof updateTimeRange; updateTimeRange: typeof updateTimeRange;
range: TimeRange; range: TimeRange;
absoluteRange: AbsoluteTimeRange; absoluteRange: AbsoluteTimeRange;
setPausedStateAction: typeof setPausedStateAction;
isPaused: boolean; isPaused: boolean;
} }
...@@ -63,22 +58,6 @@ export class LogsContainer extends PureComponent<LogsContainerProps> { ...@@ -63,22 +58,6 @@ export class LogsContainer extends PureComponent<LogsContainerProps> {
updateTimeRange({ exploreId, absoluteRange }); 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) => { handleDedupStrategyChange = (dedupStrategy: LogsDedupStrategy) => {
this.props.changeDedupStrategy(this.props.exploreId, dedupStrategy); this.props.changeDedupStrategy(this.props.exploreId, dedupStrategy);
}; };
...@@ -116,20 +95,25 @@ export class LogsContainer extends PureComponent<LogsContainerProps> { ...@@ -116,20 +95,25 @@ export class LogsContainer extends PureComponent<LogsContainerProps> {
range, range,
width, width,
isLive, isLive,
exploreId,
} = this.props; } = this.props;
return ( return (
<> <>
<LogsCrossFadeTransition visible={isLive}> <LogsCrossFadeTransition visible={isLive}>
<Collapse label="Logs" loading={false} isOpen> <Collapse label="Logs" loading={false} isOpen>
<LiveLogsWithTheme <LiveTailControls exploreId={exploreId}>
logsResult={logsResult} {controls => (
timeZone={timeZone} <LiveLogsWithTheme
stopLive={this.onStopLive} logsResult={logsResult}
isPaused={this.props.isPaused} timeZone={timeZone}
onPause={this.onPause} stopLive={controls.stop}
onResume={this.onResume} isPaused={this.props.isPaused}
/> onPause={controls.pause}
onResume={controls.resume}
/>
)}
</LiveTailControls>
</Collapse> </Collapse>
</LogsCrossFadeTransition> </LogsCrossFadeTransition>
<LogsCrossFadeTransition visible={!isLive}> <LogsCrossFadeTransition visible={!isLive}>
...@@ -198,9 +182,7 @@ function mapStateToProps(state: StoreState, { exploreId }: { exploreId: string } ...@@ -198,9 +182,7 @@ function mapStateToProps(state: StoreState, { exploreId }: { exploreId: string }
const mapDispatchToProps = { const mapDispatchToProps = {
changeDedupStrategy, changeDedupStrategy,
toggleLogLevelAction, toggleLogLevelAction,
stopLive: changeRefreshIntervalAction,
updateTimeRange, updateTimeRange,
setPausedStateAction,
}; };
export default hot(module)( export default hot(module)(
......
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<typeof useLiveTailControls>) => 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);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment