mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Explore: Refactor graph component to use PanelRenderer (#38914)
* Move SplitOpenFn type to grafana-data * Use panel renderer instead of Timeseries panel for graph in Explore * rename splitopen props on panel context
This commit is contained in:
parent
ddd110d0b2
commit
94f1173824
@ -1,4 +1,5 @@
|
||||
import { RawTimeRange } from './time';
|
||||
import { DataQuery } from './query';
|
||||
import { RawTimeRange, TimeRange } from './time';
|
||||
|
||||
/** @internal */
|
||||
export interface ExploreUrlState {
|
||||
@ -8,3 +9,10 @@ export interface ExploreUrlState {
|
||||
originPanelId?: number;
|
||||
context?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* SplitOpen type is used in Explore and related components.
|
||||
*/
|
||||
export type SplitOpen = <T extends DataQuery = any>(
|
||||
options?: { datasourceUid: string; query: T; range?: TimeRange } | undefined
|
||||
) => void;
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { EventBusSrv, EventBus, DashboardCursorSync, AnnotationEventUIModel } from '@grafana/data';
|
||||
import { AnnotationEventUIModel, DashboardCursorSync, EventBus, EventBusSrv, SplitOpen } from '@grafana/data';
|
||||
import React from 'react';
|
||||
import { SeriesVisibilityChangeMode } from '.';
|
||||
|
||||
@ -22,6 +22,11 @@ export interface PanelContext {
|
||||
onAnnotationCreate?: (annotation: AnnotationEventUIModel) => void;
|
||||
onAnnotationUpdate?: (annotation: AnnotationEventUIModel) => void;
|
||||
onAnnotationDelete?: (id: string) => void;
|
||||
/**
|
||||
* onSplitOpen is used in Explore to open the split view. It can be used in panels which has intercations and used in Explore as well.
|
||||
* For example TimeSeries panel.
|
||||
*/
|
||||
onSplitOpen?: SplitOpen;
|
||||
}
|
||||
|
||||
export const PanelContextRoot = React.createContext<PanelContext>({
|
||||
|
@ -5,7 +5,6 @@ import { connect, ConnectedProps } from 'react-redux';
|
||||
import AutoSizer from 'react-virtualized-auto-sizer';
|
||||
import memoizeOne from 'memoize-one';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
import { TooltipDisplayMode } from '@grafana/schema';
|
||||
import { ErrorBoundaryAlert, CustomScrollbar, Collapse, withTheme2, Themeable2 } from '@grafana/ui';
|
||||
import { AbsoluteTimeRange, DataQuery, LoadingState, RawTimeRange, DataFrame, GrafanaTheme2 } from '@grafana/data';
|
||||
|
||||
@ -25,10 +24,10 @@ import { NoDataSourceCallToAction } from './NoDataSourceCallToAction';
|
||||
import { getTimeZone } from '../profile/state/selectors';
|
||||
import { SecondaryActions } from './SecondaryActions';
|
||||
import { FILTER_FOR_OPERATOR, FILTER_OUT_OPERATOR, FilterItem } from '@grafana/ui/src/components/Table/types';
|
||||
import { ExploreGraphNGPanel } from './ExploreGraphNGPanel';
|
||||
import { NodeGraphContainer } from './NodeGraphContainer';
|
||||
import { ResponseErrorContainer } from './ResponseErrorContainer';
|
||||
import { TraceViewContainer } from './TraceView/TraceViewContainer';
|
||||
import { ExploreGraph } from './ExploreGraph';
|
||||
|
||||
const getStyles = (theme: GrafanaTheme2) => {
|
||||
return {
|
||||
@ -191,16 +190,15 @@ export class Explore extends React.PureComponent<Props, ExploreState> {
|
||||
const spacing = parseInt(theme.spacing(2).slice(0, -2), 10);
|
||||
return (
|
||||
<Collapse label="Graph" loading={loading} isOpen>
|
||||
<ExploreGraphNGPanel
|
||||
<ExploreGraph
|
||||
data={graphResult!}
|
||||
height={400}
|
||||
width={width - spacing}
|
||||
tooltipDisplayMode={TooltipDisplayMode.Single}
|
||||
absoluteRange={absoluteRange}
|
||||
timeZone={timeZone}
|
||||
onUpdateTimeRange={this.onUpdateTimeRange}
|
||||
annotations={queryResponse.annotations}
|
||||
splitOpenFn={splitOpen}
|
||||
loadingState={queryResponse.state}
|
||||
/>
|
||||
</Collapse>
|
||||
);
|
||||
@ -219,11 +217,12 @@ export class Explore extends React.PureComponent<Props, ExploreState> {
|
||||
}
|
||||
|
||||
renderLogsPanel(width: number) {
|
||||
const { exploreId, syncedTimes, theme } = this.props;
|
||||
const { exploreId, syncedTimes, theme, queryResponse } = this.props;
|
||||
const spacing = parseInt(theme.spacing(2).slice(0, -2), 10);
|
||||
return (
|
||||
<LogsContainer
|
||||
exploreId={exploreId}
|
||||
loadingState={queryResponse.state}
|
||||
syncedTimes={syncedTimes}
|
||||
width={width - spacing}
|
||||
onClickFilterLabel={this.onClickFilterLabel}
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { css, cx } from '@emotion/css';
|
||||
import {
|
||||
AbsoluteTimeRange,
|
||||
applyFieldOverrides,
|
||||
@ -6,36 +7,31 @@ import {
|
||||
createFieldConfigRegistry,
|
||||
DataFrame,
|
||||
dateTime,
|
||||
Field,
|
||||
FieldColorModeId,
|
||||
FieldConfigSource,
|
||||
getFrameDisplayName,
|
||||
GrafanaTheme2,
|
||||
LoadingState,
|
||||
SplitOpen,
|
||||
TimeZone,
|
||||
} from '@grafana/data';
|
||||
import { PanelRenderer } from '@grafana/runtime';
|
||||
import { GraphDrawStyle, LegendDisplayMode, TooltipDisplayMode } from '@grafana/schema';
|
||||
import {
|
||||
Icon,
|
||||
PanelContext,
|
||||
PanelContextProvider,
|
||||
SeriesVisibilityChangeMode,
|
||||
TimeSeries,
|
||||
TooltipPlugin,
|
||||
useStyles2,
|
||||
useTheme2,
|
||||
ZoomPlugin,
|
||||
} from '@grafana/ui';
|
||||
import { LegendDisplayMode, TooltipDisplayMode, GraphDrawStyle } from '@grafana/schema';
|
||||
import { defaultGraphConfig, getGraphFieldConfig } from 'app/plugins/panel/timeseries/config';
|
||||
import { ContextMenuPlugin } from 'app/plugins/panel/timeseries/plugins/ContextMenuPlugin';
|
||||
import { ExemplarsPlugin } from 'app/plugins/panel/timeseries/plugins/ExemplarsPlugin';
|
||||
import { css, cx } from '@emotion/css';
|
||||
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { getFieldLinksForExplore } from './utils/links';
|
||||
import { usePrevious } from 'react-use';
|
||||
import appEvents from 'app/core/app_events';
|
||||
import { seriesVisibilityConfigFactory } from '../dashboard/dashgrid/SeriesVisibilityConfigFactory';
|
||||
import { defaultGraphConfig, getGraphFieldConfig } from 'app/plugins/panel/timeseries/config';
|
||||
import { TimeSeriesOptions } from 'app/plugins/panel/timeseries/types';
|
||||
import { identity } from 'lodash';
|
||||
import { SplitOpen } from 'app/types/explore';
|
||||
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { usePrevious } from 'react-use';
|
||||
import { seriesVisibilityConfigFactory } from '../dashboard/dashgrid/SeriesVisibilityConfigFactory';
|
||||
|
||||
const MAX_NUMBER_OF_TIME_SERIES = 20;
|
||||
|
||||
@ -43,26 +39,26 @@ interface Props {
|
||||
data: DataFrame[];
|
||||
height: number;
|
||||
width: number;
|
||||
annotations?: DataFrame[];
|
||||
absoluteRange: AbsoluteTimeRange;
|
||||
timeZone: TimeZone;
|
||||
onUpdateTimeRange: (absoluteRange: AbsoluteTimeRange) => void;
|
||||
loadingState: LoadingState;
|
||||
annotations?: DataFrame[];
|
||||
onHiddenSeriesChanged?: (hiddenSeries: string[]) => void;
|
||||
tooltipDisplayMode: TooltipDisplayMode;
|
||||
tooltipDisplayMode?: TooltipDisplayMode;
|
||||
splitOpenFn?: SplitOpen;
|
||||
}
|
||||
|
||||
export function ExploreGraphNGPanel({
|
||||
export function ExploreGraph({
|
||||
data,
|
||||
height,
|
||||
width,
|
||||
timeZone,
|
||||
absoluteRange,
|
||||
onUpdateTimeRange,
|
||||
loadingState,
|
||||
annotations,
|
||||
tooltipDisplayMode,
|
||||
splitOpenFn,
|
||||
onHiddenSeriesChanged,
|
||||
splitOpenFn,
|
||||
tooltipDisplayMode = TooltipDisplayMode.Single,
|
||||
}: Props) {
|
||||
const theme = useTheme2();
|
||||
const [showAllTimeSeries, setShowAllTimeSeries] = useState(false);
|
||||
@ -128,12 +124,9 @@ export function ExploreGraphNGPanel({
|
||||
|
||||
const seriesToShow = showAllTimeSeries ? dataWithConfig : dataWithConfig.slice(0, MAX_NUMBER_OF_TIME_SERIES);
|
||||
|
||||
const getFieldLinks = (field: Field, rowIndex: number) => {
|
||||
return getFieldLinksForExplore({ field, rowIndex, splitOpenFn, range: timeRange });
|
||||
};
|
||||
|
||||
const panelContext: PanelContext = {
|
||||
eventBus: appEvents,
|
||||
onSplitOpen: splitOpenFn,
|
||||
onToggleSeriesVisibility(label: string, mode: SeriesVisibilityChangeMode) {
|
||||
setBaseStructureRev((r) => r + 1);
|
||||
setFieldConfig(seriesVisibilityConfigFactory(label, mode, fieldConfig, data));
|
||||
@ -155,33 +148,19 @@ export function ExploreGraphNGPanel({
|
||||
>{`Show all ${dataWithConfig.length}`}</span>
|
||||
</div>
|
||||
)}
|
||||
<TimeSeries
|
||||
frames={seriesToShow}
|
||||
structureRev={structureRev}
|
||||
<PanelRenderer
|
||||
data={{ series: seriesToShow, timeRange, structureRev, state: loadingState, annotations }}
|
||||
pluginId="timeseries"
|
||||
title=""
|
||||
width={width}
|
||||
height={height}
|
||||
timeRange={timeRange}
|
||||
legend={{ displayMode: LegendDisplayMode.List, placement: 'bottom', calcs: [] }}
|
||||
timeZone={timeZone}
|
||||
>
|
||||
{(config, alignedDataFrame) => {
|
||||
return (
|
||||
<>
|
||||
<ZoomPlugin config={config} onZoom={onUpdateTimeRange} />
|
||||
<TooltipPlugin config={config} data={alignedDataFrame} mode={tooltipDisplayMode} timeZone={timeZone} />
|
||||
<ContextMenuPlugin config={config} data={alignedDataFrame} timeZone={timeZone} />
|
||||
{annotations && (
|
||||
<ExemplarsPlugin
|
||||
config={config}
|
||||
exemplars={annotations}
|
||||
timeZone={timeZone}
|
||||
getFieldLinks={getFieldLinks}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}}
|
||||
</TimeSeries>
|
||||
options={
|
||||
{
|
||||
tooltip: { mode: tooltipDisplayMode },
|
||||
legend: { displayMode: LegendDisplayMode.List, placement: 'bottom', calcs: [] },
|
||||
} as TimeSeriesOptions
|
||||
}
|
||||
/>
|
||||
</PanelContextProvider>
|
||||
);
|
||||
}
|
@ -19,6 +19,7 @@ import {
|
||||
DataQuery,
|
||||
DataFrame,
|
||||
GrafanaTheme2,
|
||||
LoadingState,
|
||||
} from '@grafana/data';
|
||||
import {
|
||||
RadioButtonGroup,
|
||||
@ -35,7 +36,7 @@ import { dedupLogRows, filterLogLevels } from 'app/core/logs_model';
|
||||
import { LogsMetaRow } from './LogsMetaRow';
|
||||
import LogsNavigation from './LogsNavigation';
|
||||
import { RowContextOptions } from '@grafana/ui/src/components/Logs/LogRowContextProvider';
|
||||
import { ExploreGraphNGPanel } from './ExploreGraphNGPanel';
|
||||
import { ExploreGraph } from './ExploreGraph';
|
||||
|
||||
const SETTINGS_KEYS = {
|
||||
showLabels: 'grafana.explore.logs.showLabels',
|
||||
@ -54,6 +55,7 @@ interface Props extends Themeable2 {
|
||||
theme: GrafanaTheme2;
|
||||
highlighterExpressions?: string[];
|
||||
loading: boolean;
|
||||
loadingState: LoadingState;
|
||||
absoluteRange: AbsoluteTimeRange;
|
||||
timeZone: TimeZone;
|
||||
scanning?: boolean;
|
||||
@ -254,6 +256,7 @@ export class UnthemedLogs extends PureComponent<Props, State> {
|
||||
visibleRange,
|
||||
highlighterExpressions,
|
||||
loading = false,
|
||||
loadingState,
|
||||
onClickFilterLabel,
|
||||
onClickFilterOutLabel,
|
||||
timeZone,
|
||||
@ -297,14 +300,14 @@ export class UnthemedLogs extends PureComponent<Props, State> {
|
||||
This datasource does not support full-range histograms. The graph is based on the logs seen in the response.
|
||||
</div>
|
||||
{logsSeries && logsSeries.length ? (
|
||||
<ExploreGraphNGPanel
|
||||
<ExploreGraph
|
||||
data={logsSeries}
|
||||
height={150}
|
||||
width={width}
|
||||
tooltipDisplayMode={TooltipDisplayMode.Multi}
|
||||
absoluteRange={visibleRange || absoluteRange}
|
||||
timeZone={timeZone}
|
||||
onUpdateTimeRange={onChangeTime}
|
||||
loadingState={loadingState}
|
||||
onHiddenSeriesChanged={this.onToggleLogLevel}
|
||||
/>
|
||||
) : undefined}
|
||||
|
@ -2,7 +2,7 @@ import React, { PureComponent } from 'react';
|
||||
import { connect, ConnectedProps } from 'react-redux';
|
||||
import { css } from 'emotion';
|
||||
import { Collapse } from '@grafana/ui';
|
||||
import { AbsoluteTimeRange, Field, LogRowModel, RawTimeRange } from '@grafana/data';
|
||||
import { AbsoluteTimeRange, Field, LoadingState, LogRowModel, RawTimeRange } from '@grafana/data';
|
||||
import { ExploreId, ExploreItemState } from 'app/types/explore';
|
||||
import { StoreState } from 'app/types';
|
||||
import { splitOpen } from './state/main';
|
||||
@ -20,6 +20,7 @@ interface LogsContainerProps extends PropsFromRedux {
|
||||
exploreId: ExploreId;
|
||||
scanRange?: RawTimeRange;
|
||||
syncedTimes: boolean;
|
||||
loadingState: LoadingState;
|
||||
onClickFilterLabel?: (key: string, value: string) => void;
|
||||
onClickFilterOutLabel?: (key: string, value: string) => void;
|
||||
onStartScanning: () => void;
|
||||
@ -60,6 +61,7 @@ export class LogsContainer extends PureComponent<LogsContainerProps> {
|
||||
render() {
|
||||
const {
|
||||
loading,
|
||||
loadingState,
|
||||
logsHighlighterExpressions,
|
||||
logRows,
|
||||
logsMeta,
|
||||
@ -123,6 +125,7 @@ export class LogsContainer extends PureComponent<LogsContainerProps> {
|
||||
width={width}
|
||||
highlighterExpressions={logsHighlighterExpressions}
|
||||
loading={loading}
|
||||
loadingState={loadingState}
|
||||
onChangeTime={this.onChangeTime}
|
||||
onClickFilterLabel={onClickFilterLabel}
|
||||
onClickFilterOutLabel={onClickFilterOutLabel}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { DataFrame, DataFrameView, TraceSpanRow } from '@grafana/data';
|
||||
import { DataFrame, DataFrameView, SplitOpen, TraceSpanRow } from '@grafana/data';
|
||||
import { colors, useTheme } from '@grafana/ui';
|
||||
import {
|
||||
ThemeOptions,
|
||||
@ -17,7 +17,7 @@ import { TraceToLogsData } from 'app/core/components/TraceToLogsSettings';
|
||||
import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
|
||||
import { getTimeZone } from 'app/features/profile/state/selectors';
|
||||
import { StoreState } from 'app/types';
|
||||
import { ExploreId, SplitOpen } from 'app/types/explore';
|
||||
import { ExploreId } from 'app/types/explore';
|
||||
import React, { useCallback, useMemo, useState } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { createSpanLinkFactory } from './createSpanLink';
|
||||
|
@ -1,8 +1,8 @@
|
||||
import React from 'react';
|
||||
import { Collapse } from '@grafana/ui';
|
||||
import { DataFrame } from '@grafana/data';
|
||||
import { DataFrame, SplitOpen } from '@grafana/data';
|
||||
import { TraceView } from './TraceView';
|
||||
import { ExploreId, SplitOpen } from '../../../types';
|
||||
import { ExploreId } from 'app/types/explore';
|
||||
|
||||
interface Props {
|
||||
dataFrames: DataFrame[];
|
||||
|
@ -1,10 +1,9 @@
|
||||
import { DataLink, dateTime, Field, mapInternalLinkToExplore, rangeUtil, TimeRange } from '@grafana/data';
|
||||
import { DataLink, dateTime, Field, mapInternalLinkToExplore, rangeUtil, SplitOpen, TimeRange } from '@grafana/data';
|
||||
import { getTemplateSrv } from '@grafana/runtime';
|
||||
import { Icon } from '@grafana/ui';
|
||||
import { TraceSpan } from '@jaegertracing/jaeger-ui-components';
|
||||
import { TraceToLogsOptions } from 'app/core/components/TraceToLogsSettings';
|
||||
import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
|
||||
import { SplitOpen } from 'app/types/explore';
|
||||
import React from 'react';
|
||||
import { LokiQuery } from '../../../plugins/datasource/loki/types';
|
||||
|
||||
|
@ -8,9 +8,9 @@ import {
|
||||
ScopedVars,
|
||||
DataFrame,
|
||||
getFieldDisplayValuesProxy,
|
||||
SplitOpen,
|
||||
} from '@grafana/data';
|
||||
import { getTemplateSrv } from '@grafana/runtime';
|
||||
import { SplitOpen } from 'app/types/explore';
|
||||
import { getLinkSrv } from '../../panel/panellinks/link_srv';
|
||||
import { contextSrv } from 'app/core/services/context_srv';
|
||||
|
||||
|
@ -23,10 +23,10 @@ export const TimeSeriesPanel: React.FC<TimeSeriesPanelProps> = ({
|
||||
onChangeTimeRange,
|
||||
replaceVariables,
|
||||
}) => {
|
||||
const { sync, canAddAnnotations } = usePanelContext();
|
||||
const { sync, canAddAnnotations, onSplitOpen } = usePanelContext();
|
||||
|
||||
const getFieldLinks = (field: Field, rowIndex: number) => {
|
||||
return getFieldLinksForExplore({ field, rowIndex, range: timeRange });
|
||||
return getFieldLinksForExplore({ field, rowIndex, splitOpenFn: onSplitOpen, range: timeRange });
|
||||
};
|
||||
|
||||
const { frames, warn } = useMemo(() => prepareGraphableFields(data?.series, config.theme2), [data]);
|
||||
|
@ -204,7 +204,3 @@ export interface ExplorePanelData extends PanelData {
|
||||
tableResult: DataFrame | null;
|
||||
logsResult: LogsModel | null;
|
||||
}
|
||||
|
||||
export type SplitOpen = <T extends DataQuery = any>(
|
||||
options?: { datasourceUid: string; query: T; range?: TimeRange } | undefined
|
||||
) => void;
|
||||
|
Loading…
Reference in New Issue
Block a user