mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Explore: Refactor live tail controls (#19328)
This commit is contained in:
parent
22c6401867
commit
b0d6ac5f42
@ -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 {
|
|||||||
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';
|
|||||||
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 {
|
|||||||
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, {}> {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
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, {}> {
|
|||||||
|
|
||||||
{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 = {
|
|||||||
split: splitOpen,
|
split: splitOpen,
|
||||||
changeMode: changeMode,
|
changeMode: changeMode,
|
||||||
clearOrigin,
|
clearOrigin,
|
||||||
changeRefreshIntervalAction,
|
|
||||||
setPausedStateAction,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ExploreToolbar = hot(module)(
|
export const ExploreToolbar = hot(module)(
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
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';
|
|||||||
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 {
|
|||||||
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> {
|
|||||||
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> {
|
|||||||
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 }
|
|||||||
const mapDispatchToProps = {
|
const mapDispatchToProps = {
|
||||||
changeDedupStrategy,
|
changeDedupStrategy,
|
||||||
toggleLogLevelAction,
|
toggleLogLevelAction,
|
||||||
stopLive: changeRefreshIntervalAction,
|
|
||||||
updateTimeRange,
|
updateTimeRange,
|
||||||
setPausedStateAction,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default hot(module)(
|
export default hot(module)(
|
||||||
|
57
public/app/features/explore/useLiveTailControls.ts
Normal file
57
public/app/features/explore/useLiveTailControls.ts
Normal file
@ -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<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);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user