mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Explore: Fix shared crosshair for logs, logsvolume and graph panels (#57892)
* Explore: enable shared corsshair for logs, logsvolume & graph panel * avoid recreating a scoped bus on every render
This commit is contained in:
parent
3558cadb7e
commit
e6b088fbf5
@ -3897,9 +3897,6 @@ exports[`better eslint`] = {
|
|||||||
"public/app/features/explore/Explore.test.tsx:5381": [
|
"public/app/features/explore/Explore.test.tsx:5381": [
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
||||||
],
|
],
|
||||||
"public/app/features/explore/Explore.tsx:5381": [
|
|
||||||
[0, 0, 0, "Do not use any type assertions.", "0"]
|
|
||||||
],
|
|
||||||
"public/app/features/explore/ExploreGraph.tsx:5381": [
|
"public/app/features/explore/ExploreGraph.tsx:5381": [
|
||||||
[0, 0, 0, "Do not use any type assertions.", "0"]
|
[0, 0, 0, "Do not use any type assertions.", "0"]
|
||||||
],
|
],
|
||||||
|
@ -3,7 +3,7 @@ import React from 'react';
|
|||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
import { AutoSizerProps } from 'react-virtualized-auto-sizer';
|
import { AutoSizerProps } from 'react-virtualized-auto-sizer';
|
||||||
|
|
||||||
import { DataSourceApi, LoadingState, CoreApp, createTheme } from '@grafana/data';
|
import { DataSourceApi, LoadingState, CoreApp, createTheme, EventBusSrv } from '@grafana/data';
|
||||||
import { configureStore } from 'app/store/configureStore';
|
import { configureStore } from 'app/store/configureStore';
|
||||||
import { ExploreId } from 'app/types/explore';
|
import { ExploreId } from 'app/types/explore';
|
||||||
|
|
||||||
@ -86,6 +86,7 @@ const dummyProps: Props = {
|
|||||||
splitted: false,
|
splitted: false,
|
||||||
changeGraphStyle: () => {},
|
changeGraphStyle: () => {},
|
||||||
graphStyle: 'lines',
|
graphStyle: 'lines',
|
||||||
|
eventBus: new EventBusSrv(),
|
||||||
};
|
};
|
||||||
|
|
||||||
jest.mock('@grafana/runtime/src/services/dataSourceSrv', () => {
|
jest.mock('@grafana/runtime/src/services/dataSourceSrv', () => {
|
||||||
|
@ -4,7 +4,6 @@ import memoizeOne from 'memoize-one';
|
|||||||
import React, { createRef } from 'react';
|
import React, { createRef } from 'react';
|
||||||
import { connect, ConnectedProps } from 'react-redux';
|
import { connect, ConnectedProps } from 'react-redux';
|
||||||
import AutoSizer from 'react-virtualized-auto-sizer';
|
import AutoSizer from 'react-virtualized-auto-sizer';
|
||||||
import { compose } from 'redux';
|
|
||||||
import { Unsubscribable } from 'rxjs';
|
import { Unsubscribable } from 'rxjs';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@ -14,6 +13,7 @@ import {
|
|||||||
LoadingState,
|
LoadingState,
|
||||||
QueryFixAction,
|
QueryFixAction,
|
||||||
RawTimeRange,
|
RawTimeRange,
|
||||||
|
EventBus,
|
||||||
SplitOpenOptions,
|
SplitOpenOptions,
|
||||||
} from '@grafana/data';
|
} from '@grafana/data';
|
||||||
import { selectors } from '@grafana/e2e-selectors';
|
import { selectors } from '@grafana/e2e-selectors';
|
||||||
@ -87,6 +87,7 @@ const getStyles = (theme: GrafanaTheme2) => {
|
|||||||
export interface ExploreProps extends Themeable2 {
|
export interface ExploreProps extends Themeable2 {
|
||||||
exploreId: ExploreId;
|
exploreId: ExploreId;
|
||||||
theme: GrafanaTheme2;
|
theme: GrafanaTheme2;
|
||||||
|
eventBus: EventBus;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ExploreDrawer {
|
enum ExploreDrawer {
|
||||||
@ -128,12 +129,16 @@ export class Explore extends React.PureComponent<Props, ExploreState> {
|
|||||||
scrollElement: HTMLDivElement | undefined;
|
scrollElement: HTMLDivElement | undefined;
|
||||||
absoluteTimeUnsubsciber: Unsubscribable | undefined;
|
absoluteTimeUnsubsciber: Unsubscribable | undefined;
|
||||||
topOfViewRef = createRef<HTMLDivElement>();
|
topOfViewRef = createRef<HTMLDivElement>();
|
||||||
|
graphEventBus: EventBus;
|
||||||
|
logsEventBus: EventBus;
|
||||||
|
|
||||||
constructor(props: Props) {
|
constructor(props: Props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
openDrawer: undefined,
|
openDrawer: undefined,
|
||||||
};
|
};
|
||||||
|
this.graphEventBus = props.eventBus.newScopedBus('graph', { onlyLocal: false });
|
||||||
|
this.logsEventBus = props.eventBus.newScopedBus('logs', { onlyLocal: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
@ -291,6 +296,7 @@ export class Explore extends React.PureComponent<Props, ExploreState> {
|
|||||||
splitOpenFn={this.onSplitOpen('graph')}
|
splitOpenFn={this.onSplitOpen('graph')}
|
||||||
loadingState={queryResponse.state}
|
loadingState={queryResponse.state}
|
||||||
anchorToZero={false}
|
anchorToZero={false}
|
||||||
|
eventBus={this.graphEventBus}
|
||||||
/>
|
/>
|
||||||
</Collapse>
|
</Collapse>
|
||||||
);
|
);
|
||||||
@ -324,6 +330,7 @@ export class Explore extends React.PureComponent<Props, ExploreState> {
|
|||||||
onStartScanning={this.onStartScanning}
|
onStartScanning={this.onStartScanning}
|
||||||
onStopScanning={this.onStopScanning}
|
onStopScanning={this.onStopScanning}
|
||||||
scrollElement={this.scrollElement}
|
scrollElement={this.scrollElement}
|
||||||
|
eventBus={this.logsEventBus}
|
||||||
splitOpenFn={this.onSplitOpen('logs')}
|
splitOpenFn={this.onSplitOpen('logs')}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@ -550,4 +557,4 @@ const mapDispatchToProps = {
|
|||||||
|
|
||||||
const connector = connect(mapStateToProps, mapDispatchToProps);
|
const connector = connect(mapStateToProps, mapDispatchToProps);
|
||||||
|
|
||||||
export default compose(connector, withTheme2)(Explore) as React.ComponentType<{ exploreId: ExploreId }>;
|
export default withTheme2(connector(Explore));
|
||||||
|
@ -18,6 +18,8 @@ import {
|
|||||||
LoadingState,
|
LoadingState,
|
||||||
SplitOpen,
|
SplitOpen,
|
||||||
TimeZone,
|
TimeZone,
|
||||||
|
DashboardCursorSync,
|
||||||
|
EventBus,
|
||||||
} from '@grafana/data';
|
} from '@grafana/data';
|
||||||
import { PanelRenderer } from '@grafana/runtime';
|
import { PanelRenderer } from '@grafana/runtime';
|
||||||
import { GraphDrawStyle, LegendDisplayMode, TooltipDisplayMode, SortOrder } from '@grafana/schema';
|
import { GraphDrawStyle, LegendDisplayMode, TooltipDisplayMode, SortOrder } from '@grafana/schema';
|
||||||
@ -29,7 +31,6 @@ import {
|
|||||||
useStyles2,
|
useStyles2,
|
||||||
useTheme2,
|
useTheme2,
|
||||||
} from '@grafana/ui';
|
} from '@grafana/ui';
|
||||||
import appEvents from 'app/core/app_events';
|
|
||||||
import { defaultGraphConfig, getGraphFieldConfig } from 'app/plugins/panel/timeseries/config';
|
import { defaultGraphConfig, getGraphFieldConfig } from 'app/plugins/panel/timeseries/config';
|
||||||
import { TimeSeriesOptions } from 'app/plugins/panel/timeseries/types';
|
import { TimeSeriesOptions } from 'app/plugins/panel/timeseries/types';
|
||||||
|
|
||||||
@ -54,6 +55,7 @@ interface Props {
|
|||||||
onChangeTime: (timeRange: AbsoluteTimeRange) => void;
|
onChangeTime: (timeRange: AbsoluteTimeRange) => void;
|
||||||
graphStyle: ExploreGraphStyle;
|
graphStyle: ExploreGraphStyle;
|
||||||
anchorToZero: boolean;
|
anchorToZero: boolean;
|
||||||
|
eventBus: EventBus;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ExploreGraph({
|
export function ExploreGraph({
|
||||||
@ -70,6 +72,7 @@ export function ExploreGraph({
|
|||||||
graphStyle,
|
graphStyle,
|
||||||
tooltipDisplayMode = TooltipDisplayMode.Single,
|
tooltipDisplayMode = TooltipDisplayMode.Single,
|
||||||
anchorToZero,
|
anchorToZero,
|
||||||
|
eventBus,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const theme = useTheme2();
|
const theme = useTheme2();
|
||||||
const [showAllTimeSeries, setShowAllTimeSeries] = useState(false);
|
const [showAllTimeSeries, setShowAllTimeSeries] = useState(false);
|
||||||
@ -142,7 +145,8 @@ export function ExploreGraph({
|
|||||||
const seriesToShow = showAllTimeSeries ? dataWithConfig : dataWithConfig.slice(0, MAX_NUMBER_OF_TIME_SERIES);
|
const seriesToShow = showAllTimeSeries ? dataWithConfig : dataWithConfig.slice(0, MAX_NUMBER_OF_TIME_SERIES);
|
||||||
|
|
||||||
const panelContext: PanelContext = {
|
const panelContext: PanelContext = {
|
||||||
eventBus: appEvents,
|
eventBus,
|
||||||
|
sync: () => DashboardCursorSync.Crosshair,
|
||||||
onSplitOpen: splitOpenFn,
|
onSplitOpen: splitOpenFn,
|
||||||
onToggleSeriesVisibility(label: string, mode: SeriesVisibilityChangeMode) {
|
onToggleSeriesVisibility(label: string, mode: SeriesVisibilityChangeMode) {
|
||||||
setBaseStructureRev((r) => r + 1);
|
setBaseStructureRev((r) => r + 1);
|
||||||
|
@ -3,7 +3,7 @@ import memoizeOne from 'memoize-one';
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { connect, ConnectedProps } from 'react-redux';
|
import { connect, ConnectedProps } from 'react-redux';
|
||||||
|
|
||||||
import { ExploreUrlState, EventBusExtended, EventBusSrv, GrafanaTheme2 } from '@grafana/data';
|
import { ExploreUrlState, EventBusExtended, EventBusSrv, GrafanaTheme2, EventBus } from '@grafana/data';
|
||||||
import { selectors } from '@grafana/e2e-selectors';
|
import { selectors } from '@grafana/e2e-selectors';
|
||||||
import { Themeable2, withTheme2 } from '@grafana/ui';
|
import { Themeable2, withTheme2 } from '@grafana/ui';
|
||||||
import { config } from 'app/core/config';
|
import { config } from 'app/core/config';
|
||||||
@ -50,6 +50,7 @@ interface OwnProps extends Themeable2 {
|
|||||||
exploreId: ExploreId;
|
exploreId: ExploreId;
|
||||||
urlQuery: string;
|
urlQuery: string;
|
||||||
split: boolean;
|
split: boolean;
|
||||||
|
eventBus: EventBus;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Props extends OwnProps, ConnectedProps<typeof connector> {}
|
interface Props extends OwnProps, ConnectedProps<typeof connector> {}
|
||||||
@ -143,12 +144,12 @@ class ExplorePaneContainerUnconnected extends React.PureComponent<Props> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { theme, split, exploreId, initialized } = this.props;
|
const { theme, split, exploreId, initialized, eventBus } = this.props;
|
||||||
const styles = getStyles(theme);
|
const styles = getStyles(theme);
|
||||||
const exploreClass = cx(styles.explore, split && styles.exploreSplit);
|
const exploreClass = cx(styles.explore, split && styles.exploreSplit);
|
||||||
return (
|
return (
|
||||||
<div className={exploreClass} ref={this.getRef} data-testid={selectors.pages.Explore.General.container}>
|
<div className={exploreClass} ref={this.getRef} data-testid={selectors.pages.Explore.General.container}>
|
||||||
{initialized && <Explore exploreId={exploreId} />}
|
{initialized && <Explore exploreId={exploreId} eventBus={eventBus} />}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { render, screen, fireEvent } from '@testing-library/react';
|
import { render, screen, fireEvent } from '@testing-library/react';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { LoadingState, LogLevel, LogRowModel, MutableDataFrame, toUtc } from '@grafana/data';
|
import { LoadingState, LogLevel, LogRowModel, MutableDataFrame, toUtc, EventBusSrv } from '@grafana/data';
|
||||||
import { ExploreId } from 'app/types';
|
import { ExploreId } from 'app/types';
|
||||||
|
|
||||||
import { Logs } from './Logs';
|
import { Logs } from './Logs';
|
||||||
@ -37,6 +37,7 @@ describe('Logs', () => {
|
|||||||
getFieldLinks={() => {
|
getFieldLinks={() => {
|
||||||
return [];
|
return [];
|
||||||
}}
|
}}
|
||||||
|
eventBus={new EventBusSrv()}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -23,6 +23,9 @@ import {
|
|||||||
SplitOpen,
|
SplitOpen,
|
||||||
DataQueryResponse,
|
DataQueryResponse,
|
||||||
CoreApp,
|
CoreApp,
|
||||||
|
DataHoverEvent,
|
||||||
|
DataHoverClearEvent,
|
||||||
|
EventBus,
|
||||||
} from '@grafana/data';
|
} from '@grafana/data';
|
||||||
import { reportInteraction } from '@grafana/runtime';
|
import { reportInteraction } from '@grafana/runtime';
|
||||||
import {
|
import {
|
||||||
@ -79,6 +82,7 @@ interface Props extends Themeable2 {
|
|||||||
getFieldLinks: (field: Field, rowIndex: number) => Array<LinkModel<Field>>;
|
getFieldLinks: (field: Field, rowIndex: number) => Array<LinkModel<Field>>;
|
||||||
addResultsToCache: () => void;
|
addResultsToCache: () => void;
|
||||||
clearCache: () => void;
|
clearCache: () => void;
|
||||||
|
eventBus: EventBus;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface State {
|
interface State {
|
||||||
@ -108,6 +112,7 @@ class UnthemedLogs extends PureComponent<Props, State> {
|
|||||||
flipOrderTimer?: number;
|
flipOrderTimer?: number;
|
||||||
cancelFlippingTimer?: number;
|
cancelFlippingTimer?: number;
|
||||||
topLogsRef = createRef<HTMLDivElement>();
|
topLogsRef = createRef<HTMLDivElement>();
|
||||||
|
logsVolumeEventBus: EventBus;
|
||||||
|
|
||||||
state: State = {
|
state: State = {
|
||||||
showLabels: store.getBool(SETTINGS_KEYS.showLabels, false),
|
showLabels: store.getBool(SETTINGS_KEYS.showLabels, false),
|
||||||
@ -122,6 +127,11 @@ class UnthemedLogs extends PureComponent<Props, State> {
|
|||||||
forceEscape: false,
|
forceEscape: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
constructor(props: Props) {
|
||||||
|
super(props);
|
||||||
|
this.logsVolumeEventBus = props.eventBus.newScopedBus('logsvolume', { onlyLocal: false });
|
||||||
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
if (this.flipOrderTimer) {
|
if (this.flipOrderTimer) {
|
||||||
window.clearTimeout(this.flipOrderTimer);
|
window.clearTimeout(this.flipOrderTimer);
|
||||||
@ -132,6 +142,20 @@ class UnthemedLogs extends PureComponent<Props, State> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onLogRowHover = (row?: LogRowModel) => {
|
||||||
|
if (!row) {
|
||||||
|
this.props.eventBus.publish(new DataHoverClearEvent());
|
||||||
|
} else {
|
||||||
|
this.props.eventBus.publish(
|
||||||
|
new DataHoverEvent({
|
||||||
|
point: {
|
||||||
|
time: row.timeEpochMs,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
onChangeLogsSortOrder = () => {
|
onChangeLogsSortOrder = () => {
|
||||||
this.setState({ isFlipping: true });
|
this.setState({ isFlipping: true });
|
||||||
// we are using setTimeout here to make sure that disabled button is rendered before the rendering of reordered logs
|
// we are using setTimeout here to make sure that disabled button is rendered before the rendering of reordered logs
|
||||||
@ -367,6 +391,7 @@ class UnthemedLogs extends PureComponent<Props, State> {
|
|||||||
splitOpen={splitOpen}
|
splitOpen={splitOpen}
|
||||||
onLoadLogsVolume={() => loadLogsVolumeData(exploreId)}
|
onLoadLogsVolume={() => loadLogsVolumeData(exploreId)}
|
||||||
onHiddenSeriesChanged={this.onToggleLogLevel}
|
onHiddenSeriesChanged={this.onToggleLogLevel}
|
||||||
|
eventBus={this.logsVolumeEventBus}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Collapse>
|
</Collapse>
|
||||||
@ -480,6 +505,7 @@ class UnthemedLogs extends PureComponent<Props, State> {
|
|||||||
onClickHideDetectedField={this.hideDetectedField}
|
onClickHideDetectedField={this.hideDetectedField}
|
||||||
app={CoreApp.Explore}
|
app={CoreApp.Explore}
|
||||||
scrollElement={scrollElement}
|
scrollElement={scrollElement}
|
||||||
|
onLogRowHover={this.onLogRowHover}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<LogsNavigation
|
<LogsNavigation
|
||||||
|
@ -8,6 +8,7 @@ import {
|
|||||||
LoadingState,
|
LoadingState,
|
||||||
LogRowModel,
|
LogRowModel,
|
||||||
RawTimeRange,
|
RawTimeRange,
|
||||||
|
EventBus,
|
||||||
SplitOpen,
|
SplitOpen,
|
||||||
} from '@grafana/data';
|
} from '@grafana/data';
|
||||||
import { Collapse } from '@grafana/ui';
|
import { Collapse } from '@grafana/ui';
|
||||||
@ -35,6 +36,7 @@ interface LogsContainerProps extends PropsFromRedux {
|
|||||||
onClickFilterOutLabel?: (key: string, value: string) => void;
|
onClickFilterOutLabel?: (key: string, value: string) => void;
|
||||||
onStartScanning: () => void;
|
onStartScanning: () => void;
|
||||||
onStopScanning: () => void;
|
onStopScanning: () => void;
|
||||||
|
eventBus: EventBus;
|
||||||
splitOpenFn: SplitOpen;
|
splitOpenFn: SplitOpen;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,6 +158,7 @@ class LogsContainer extends PureComponent<LogsContainerProps> {
|
|||||||
addResultsToCache={() => addResultsToCache(exploreId)}
|
addResultsToCache={() => addResultsToCache(exploreId)}
|
||||||
clearCache={() => clearCache(exploreId)}
|
clearCache={() => clearCache(exploreId)}
|
||||||
scrollElement={scrollElement}
|
scrollElement={scrollElement}
|
||||||
|
eventBus={this.props.eventBus}
|
||||||
/>
|
/>
|
||||||
</LogsCrossFadeTransition>
|
</LogsCrossFadeTransition>
|
||||||
</>
|
</>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { render, screen } from '@testing-library/react';
|
import { render, screen } from '@testing-library/react';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { DataQueryResponse, LoadingState } from '@grafana/data';
|
import { DataQueryResponse, LoadingState, EventBusSrv } from '@grafana/data';
|
||||||
|
|
||||||
import { LogsVolumePanel } from './LogsVolumePanel';
|
import { LogsVolumePanel } from './LogsVolumePanel';
|
||||||
|
|
||||||
@ -25,6 +25,7 @@ function renderPanel(logsVolumeData?: DataQueryResponse) {
|
|||||||
logLinesBasedDataVisibleRange={undefined}
|
logLinesBasedDataVisibleRange={undefined}
|
||||||
onLoadLogsVolume={() => {}}
|
onLoadLogsVolume={() => {}}
|
||||||
onHiddenSeriesChanged={() => null}
|
onHiddenSeriesChanged={() => null}
|
||||||
|
eventBus={new EventBusSrv()}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ import {
|
|||||||
LoadingState,
|
LoadingState,
|
||||||
SplitOpen,
|
SplitOpen,
|
||||||
TimeZone,
|
TimeZone,
|
||||||
|
EventBus,
|
||||||
} from '@grafana/data';
|
} from '@grafana/data';
|
||||||
import { Alert, Button, Collapse, InlineField, TooltipDisplayMode, useStyles2, useTheme2 } from '@grafana/ui';
|
import { Alert, Button, Collapse, InlineField, TooltipDisplayMode, useStyles2, useTheme2 } from '@grafana/ui';
|
||||||
|
|
||||||
@ -25,6 +26,7 @@ type Props = {
|
|||||||
onUpdateTimeRange: (timeRange: AbsoluteTimeRange) => void;
|
onUpdateTimeRange: (timeRange: AbsoluteTimeRange) => void;
|
||||||
onLoadLogsVolume: () => void;
|
onLoadLogsVolume: () => void;
|
||||||
onHiddenSeriesChanged: (hiddenSeries: string[]) => void;
|
onHiddenSeriesChanged: (hiddenSeries: string[]) => void;
|
||||||
|
eventBus: EventBus;
|
||||||
};
|
};
|
||||||
|
|
||||||
const SHORT_ERROR_MESSAGE_LIMIT = 100;
|
const SHORT_ERROR_MESSAGE_LIMIT = 100;
|
||||||
@ -131,6 +133,7 @@ export function LogsVolumePanel(props: Props) {
|
|||||||
tooltipDisplayMode={TooltipDisplayMode.Multi}
|
tooltipDisplayMode={TooltipDisplayMode.Multi}
|
||||||
onHiddenSeriesChanged={onHiddenSeriesChanged}
|
onHiddenSeriesChanged={onHiddenSeriesChanged}
|
||||||
anchorToZero
|
anchorToZero
|
||||||
|
eventBus={props.eventBus}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { css } from '@emotion/css';
|
import { css } from '@emotion/css';
|
||||||
import React, { useEffect } from 'react';
|
import React, { useEffect, useRef } from 'react';
|
||||||
|
|
||||||
import { locationService } from '@grafana/runtime';
|
import { locationService } from '@grafana/runtime';
|
||||||
import { ErrorBoundaryAlert } from '@grafana/ui';
|
import { ErrorBoundaryAlert, usePanelContext } from '@grafana/ui';
|
||||||
import { useGrafana } from 'app/core/context/GrafanaContext';
|
import { useGrafana } from 'app/core/context/GrafanaContext';
|
||||||
import { useAppNotification } from 'app/core/copy/appNotification';
|
import { useAppNotification } from 'app/core/copy/appNotification';
|
||||||
import { useNavModel } from 'app/core/hooks/useNavModel';
|
import { useNavModel } from 'app/core/hooks/useNavModel';
|
||||||
@ -38,6 +38,8 @@ function Wrapper(props: GrafanaRouteComponentProps<{}, ExploreQueryParams>) {
|
|||||||
const navModel = useNavModel('explore');
|
const navModel = useNavModel('explore');
|
||||||
const { get } = useCorrelations();
|
const { get } = useCorrelations();
|
||||||
const { warning } = useAppNotification();
|
const { warning } = useAppNotification();
|
||||||
|
const panelCtx = usePanelContext();
|
||||||
|
const eventBus = useRef(panelCtx.eventBus.newScopedBus('explore', { onlyLocal: false }));
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
//This is needed for breadcrumbs and topnav.
|
//This is needed for breadcrumbs and topnav.
|
||||||
@ -102,11 +104,21 @@ function Wrapper(props: GrafanaRouteComponentProps<{}, ExploreQueryParams>) {
|
|||||||
<ExploreActions exploreIdLeft={ExploreId.left} exploreIdRight={ExploreId.right} />
|
<ExploreActions exploreIdLeft={ExploreId.left} exploreIdRight={ExploreId.right} />
|
||||||
<div className={styles.exploreWrapper}>
|
<div className={styles.exploreWrapper}>
|
||||||
<ErrorBoundaryAlert style="page">
|
<ErrorBoundaryAlert style="page">
|
||||||
<ExplorePaneContainer split={hasSplit} exploreId={ExploreId.left} urlQuery={queryParams.left} />
|
<ExplorePaneContainer
|
||||||
|
split={hasSplit}
|
||||||
|
exploreId={ExploreId.left}
|
||||||
|
urlQuery={queryParams.left}
|
||||||
|
eventBus={eventBus.current}
|
||||||
|
/>
|
||||||
</ErrorBoundaryAlert>
|
</ErrorBoundaryAlert>
|
||||||
{hasSplit && (
|
{hasSplit && (
|
||||||
<ErrorBoundaryAlert style="page">
|
<ErrorBoundaryAlert style="page">
|
||||||
<ExplorePaneContainer split={hasSplit} exploreId={ExploreId.right} urlQuery={queryParams.right} />
|
<ExplorePaneContainer
|
||||||
|
split={hasSplit}
|
||||||
|
exploreId={ExploreId.right}
|
||||||
|
urlQuery={queryParams.right}
|
||||||
|
eventBus={eventBus.current}
|
||||||
|
/>
|
||||||
</ErrorBoundaryAlert>
|
</ErrorBoundaryAlert>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
Reference in New Issue
Block a user