[Lens][Visualize] Adds option to disable cursor sync on dashboards (#143355)

* [Lens][Visualize] Disable cursor sync on dashboard level option

* Increase XY limits as it fails for 1B :)

* Fix jest tests

* Apply PR nit
This commit is contained in:
Stratoula Kalafateli 2022-10-17 12:33:52 +03:00 committed by GitHub
parent 12acbaca91
commit 46c1250db7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
55 changed files with 183 additions and 29 deletions

View file

@ -337,6 +337,8 @@ Apply a set of design options to the entire dashboard.
* *Sync color pallettes across panels* — Applies the same color palette to all panels on the dashboard.
* *Sync cursor across panels* — When you hover your cursor over a *Lens*, *TSVB*, aggregation-based, or *Timelion* XY chart and a heatmap chart, the cursor on all other related dashboard charts automatically appear.
* *Sync tooltips across panels* — When you hover your cursor over a *Lens*, *TSVB*, aggregation-based, or *Timelion* XY chart, the tooltips on all other related dashboard charts automatically appear.
[float]

View file

@ -49,7 +49,7 @@ pageLoadAssetSize:
expressions: 140958
expressionShape: 34008
expressionTagcloud: 27505
expressionXY: 38000
expressionXY: 38500
features: 21723
fieldFormats: 65209
files: 22673

View file

@ -101,6 +101,7 @@ Object {
],
"type": "datatable",
},
"syncCursor": true,
"syncTooltips": false,
},
}

View file

@ -231,6 +231,7 @@ export const heatmapFunction = (): HeatmapExpressionFunctionDefinition => ({
handlers.getExecutionContext?.()?.description,
},
syncTooltips: handlers?.isSyncTooltipsEnabled?.() ?? false,
syncCursor: handlers?.isSyncCursorEnabled?.() ?? true,
},
};
},

View file

@ -93,6 +93,7 @@ export interface HeatmapExpressionProps {
data: Datatable;
args: HeatmapArguments;
syncTooltips: boolean;
syncCursor: boolean;
}
export interface HeatmapRender {

View file

@ -39,5 +39,6 @@ export type HeatmapRenderProps = HeatmapExpressionProps & {
uiState: PersistedState;
interactive: boolean;
syncTooltips: boolean;
syncCursor: boolean;
renderComplete: IInterpreterRenderHandlers['done'];
};

View file

@ -125,6 +125,7 @@ describe('HeatmapComponent', function () {
formatFactory: formatService.deserialize,
interactive: true,
syncTooltips: false,
syncCursor: true,
renderComplete: jest.fn(),
};
});

View file

@ -146,6 +146,7 @@ export const HeatmapComponent: FC<HeatmapRenderProps> = memo(
uiState,
interactive,
syncTooltips,
syncCursor,
renderComplete,
}) => {
const chartRef = useRef<Chart>(null);
@ -576,7 +577,7 @@ export const HeatmapComponent: FC<HeatmapRenderProps> = memo(
noResults={
<EmptyPlaceholder icon={IconChartHeatmap} renderComplete={onRenderChange} />
}
onPointerUpdate={handleCursorUpdate}
onPointerUpdate={syncCursor ? handleCursorUpdate : undefined}
externalPointerEvents={{
tooltip: { visible: syncTooltips },
}}

View file

@ -90,6 +90,7 @@ export const heatmapRenderer: (
interactive={isInteractive()}
chartsActiveCursorService={plugins.charts.activeCursor}
syncTooltips={config.syncTooltips}
syncCursor={config.syncCursor}
/>
</div>
</KibanaThemeProvider>,

View file

@ -28,6 +28,7 @@ describe('layeredXyVis', () => {
args: { ...rest, layers: [sampleExtendedLayer] },
syncColors: false,
syncTooltips: false,
syncCursor: true,
canNavigateToLens: false,
},
});

View file

@ -64,6 +64,7 @@ export const layeredXyVisFn: LayeredXyVisFn['fn'] = async (data, args, handlers)
canNavigateToLens: Boolean(handlers.variables.canNavigateToLens),
syncColors: handlers?.isSyncColorsEnabled?.() ?? false,
syncTooltips: handlers?.isSyncTooltipsEnabled?.() ?? false,
syncCursor: handlers?.isSyncCursorEnabled?.() ?? true,
},
};
};

View file

@ -41,6 +41,7 @@ describe('xyVis', () => {
canNavigateToLens: false,
syncColors: false,
syncTooltips: false,
syncCursor: true,
},
});
});
@ -350,6 +351,7 @@ describe('xyVis', () => {
canNavigateToLens: false,
syncColors: false,
syncTooltips: false,
syncCursor: true,
},
});
});

View file

@ -139,6 +139,7 @@ export const xyVisFn: XyVisFn['fn'] = async (data, args, handlers) => {
canNavigateToLens: Boolean(handlers.variables.canNavigateToLens),
syncColors: handlers?.isSyncColorsEnabled?.() ?? false,
syncTooltips: handlers?.isSyncTooltipsEnabled?.() ?? false,
syncCursor: handlers?.isSyncCursorEnabled?.() ?? true,
},
};
};

View file

@ -17,6 +17,7 @@ import { XYProps } from './expression_functions';
export interface XYChartProps {
args: XYProps;
syncTooltips: boolean;
syncCursor: boolean;
syncColors: boolean;
canNavigateToLens?: boolean;
}

View file

@ -117,6 +117,7 @@ describe('XYChart component', () => {
onSelectRange,
syncColors: false,
syncTooltips: false,
syncCursor: true,
useLegacyTimeAxis: false,
eventAnnotationService: eventAnnotationServiceMock,
renderComplete: jest.fn(),

View file

@ -125,6 +125,7 @@ export type XYChartRenderProps = Omit<XYChartProps, 'canNavigateToLens'> & {
renderMode: RenderMode;
syncColors: boolean;
syncTooltips: boolean;
syncCursor: boolean;
eventAnnotationService: EventAnnotationServiceType;
renderComplete: () => void;
uiState?: PersistedState;
@ -199,6 +200,7 @@ export function XYChart({
interactive = true,
syncColors,
syncTooltips,
syncCursor,
useLegacyTimeAxis,
renderComplete,
uiState,
@ -753,7 +755,7 @@ export function XYChart({
/>
}
onRenderChange={onRenderChange}
onPointerUpdate={handleCursorUpdate}
onPointerUpdate={syncCursor ? handleCursorUpdate : undefined}
externalPointerEvents={{
tooltip: { visible: syncTooltips, placement: Placement.Right },
}}

View file

@ -235,6 +235,7 @@ export const getXyChartRenderer = ({
renderMode={handlers.getRenderMode()}
syncColors={config.syncColors}
syncTooltips={config.syncTooltips}
syncCursor={config.syncCursor}
uiState={handlers.uiState as PersistedState}
renderComplete={renderComplete}
/>

View file

@ -18,7 +18,12 @@ describe('calculateMinInterval', () => {
beforeEach(() => {
const { layers, ...restArgs } = sampleArgs().args;
xyProps = { args: { ...restArgs, layers }, syncColors: false, syncTooltips: false };
xyProps = {
args: { ...restArgs, layers },
syncColors: false,
syncTooltips: false,
syncCursor: true,
};
layer = xyProps.args.layers[0] as DataLayerConfig;
layer.xScaleType = 'time';
});

View file

@ -68,6 +68,7 @@ export interface InheritedChildInput extends IndexSignature {
id: string;
searchSessionId?: string;
syncColors?: boolean;
syncCursor?: boolean;
syncTooltips?: boolean;
executionContext?: KibanaExecutionContext;
}
@ -351,6 +352,7 @@ export class DashboardContainer extends Container<InheritedChildInput, Dashboard
filters,
searchSessionId,
syncColors,
syncCursor,
syncTooltips,
executionContext,
} = this.input;
@ -371,6 +373,7 @@ export class DashboardContainer extends Container<InheritedChildInput, Dashboard
searchSessionId,
syncColors,
syncTooltips,
syncCursor,
executionContext,
};
}

View file

@ -70,6 +70,7 @@ export class DashboardContainerFactoryDefinition
isFullScreenMode: false,
useMargins: true,
syncColors: true,
syncCursor: true,
syncTooltips: true,
};
}

View file

@ -41,6 +41,7 @@ const getDashboardState = (state?: Partial<DashboardState>): DashboardState => {
useMargins: true,
syncColors: false,
syncTooltips: false,
syncCursor: true,
},
panels: {
panel_1: {
@ -99,6 +100,7 @@ describe('Dashboard state diff function', () => {
useMargins: false,
syncColors: false,
syncTooltips: false,
syncCursor: true,
},
})
).toEqual(['options']);
@ -111,6 +113,7 @@ describe('Dashboard state diff function', () => {
useMargins: true,
syncColors: undefined,
syncTooltips: undefined,
syncCursor: true,
} as unknown as DashboardOptions,
})
).toEqual([]);

View file

@ -61,6 +61,9 @@ export const dashboardStateSlice = createSlice({
setSyncColors: (state, action: PayloadAction<boolean>) => {
state.options.syncColors = action.payload;
},
setSyncCursor: (state, action: PayloadAction<boolean>) => {
state.options.syncCursor = action.payload;
},
setSyncTooltips: (state, action: PayloadAction<boolean>) => {
state.options.syncTooltips = action.payload;
},
@ -128,6 +131,7 @@ export const {
setTimeRange,
setSyncColors,
setSyncTooltips,
setSyncCursor,
setUseMargins,
setViewMode,
setFilters,

View file

@ -39,6 +39,7 @@ import {
setStateFromSaveModal,
setSyncColors,
setSyncTooltips,
setSyncCursor,
setUseMargins,
setViewMode,
useDashboardDispatch,
@ -402,6 +403,10 @@ export function DashboardTopNav({
onSyncColorsChange: (isChecked: boolean) => {
dispatchDashboardStateChange(setSyncColors(isChecked));
},
syncCursor: currentState.options.syncCursor ?? true,
onSyncCursorChange: (isChecked: boolean) => {
dispatchDashboardStateChange(setSyncCursor(isChecked));
},
syncTooltips: Boolean(currentState.options.syncTooltips),
onSyncTooltipsChange: (isChecked: boolean) => {
dispatchDashboardStateChange(setSyncTooltips(isChecked));

View file

@ -18,6 +18,8 @@ interface Props {
onHidePanelTitlesChange: (hideTitles: boolean) => void;
syncColors: boolean;
onSyncColorsChange: (syncColors: boolean) => void;
syncCursor: boolean;
onSyncCursorChange: (syncCursor: boolean) => void;
syncTooltips: boolean;
onSyncTooltipsChange: (syncTooltips: boolean) => void;
}
@ -26,6 +28,7 @@ interface State {
useMargins: boolean;
hidePanelTitles: boolean;
syncColors: boolean;
syncCursor: boolean;
syncTooltips: boolean;
}
@ -34,6 +37,7 @@ export class OptionsMenu extends Component<Props, State> {
useMargins: this.props.useMargins,
hidePanelTitles: this.props.hidePanelTitles,
syncColors: this.props.syncColors,
syncCursor: this.props.syncCursor,
syncTooltips: this.props.syncTooltips,
};
@ -59,6 +63,12 @@ export class OptionsMenu extends Component<Props, State> {
this.setState({ syncColors: isChecked });
};
handleSyncCursorChange = (evt: any) => {
const isChecked = evt.target.checked;
this.props.onSyncCursorChange(isChecked);
this.setState({ syncCursor: isChecked });
};
handleSyncTooltipsChange = (evt: any) => {
const isChecked = evt.target.checked;
this.props.onSyncTooltipsChange(isChecked);
@ -89,27 +99,49 @@ export class OptionsMenu extends Component<Props, State> {
data-test-subj="dashboardPanelTitlesCheckbox"
/>
</EuiFormRow>
<EuiFormRow>
<EuiSwitch
label={i18n.translate('dashboard.topNav.options.syncColorsBetweenPanelsSwitchLabel', {
defaultMessage: 'Sync color palettes across panels',
})}
checked={this.state.syncColors}
onChange={this.handleSyncColorsChange}
data-test-subj="dashboardSyncColorsCheckbox"
/>
</EuiFormRow>
<EuiFormRow>
<EuiSwitch
label={i18n.translate('dashboard.topNav.options.syncTooltipsBetweenPanelsSwitchLabel', {
defaultMessage: 'Sync tooltips across panels',
})}
checked={this.state.syncTooltips}
onChange={this.handleSyncTooltipsChange}
data-test-subj="dashboardSyncTooltipsCheckbox"
/>
<EuiFormRow label="Sync across panels">
<>
<EuiFormRow>
<EuiSwitch
label={i18n.translate(
'dashboard.topNav.options.syncColorsBetweenPanelsSwitchLabel',
{
defaultMessage: 'Sync color palettes across panels',
}
)}
checked={this.state.syncColors}
onChange={this.handleSyncColorsChange}
data-test-subj="dashboardSyncColorsCheckbox"
/>
</EuiFormRow>
<EuiFormRow>
<EuiSwitch
label={i18n.translate(
'dashboard.topNav.options.syncCursorBetweenPanelsSwitchLabel',
{
defaultMessage: 'Sync cursor across panels',
}
)}
checked={this.state.syncCursor}
onChange={this.handleSyncCursorChange}
data-test-subj="dashboardSyncCursorCheckbox"
/>
</EuiFormRow>
<EuiFormRow>
<EuiSwitch
label={i18n.translate(
'dashboard.topNav.options.syncTooltipsBetweenPanelsSwitchLabel',
{
defaultMessage: 'Sync tooltips across panels',
}
)}
checked={this.state.syncTooltips}
disabled={!Boolean(this.state.syncCursor)}
onChange={this.handleSyncTooltipsChange}
data-test-subj="dashboardSyncTooltipsCheckbox"
/>
</EuiFormRow>
</>
</EuiFormRow>
</EuiForm>
);

View file

@ -31,6 +31,8 @@ export interface ShowOptionsPopoverProps {
onUseMarginsChange: (useMargins: boolean) => void;
syncColors: boolean;
onSyncColorsChange: (syncColors: boolean) => void;
syncCursor: boolean;
onSyncCursorChange: (syncCursor: boolean) => void;
syncTooltips: boolean;
onSyncTooltipsChange: (syncTooltips: boolean) => void;
hidePanelTitles: boolean;
@ -45,6 +47,8 @@ export function showOptionsPopover({
onHidePanelTitlesChange,
syncColors,
onSyncColorsChange,
syncCursor,
onSyncCursorChange,
syncTooltips,
onSyncTooltipsChange,
}: ShowOptionsPopoverProps) {
@ -78,6 +82,8 @@ export function showOptionsPopover({
onHidePanelTitlesChange={onHidePanelTitlesChange}
syncColors={syncColors}
onSyncColorsChange={onSyncColorsChange}
syncCursor={syncCursor}
onSyncCursorChange={onSyncCursorChange}
syncTooltips={syncTooltips}
onSyncTooltipsChange={onSyncTooltipsChange}
/>

View file

@ -109,6 +109,7 @@ describe('ShowShareModal', () => {
hidePanelTitles: true,
useMargins: true,
syncColors: true,
syncCursor: true,
syncTooltips: true,
},
filters: [

View file

@ -46,6 +46,7 @@ export const defaultDashboardState: DashboardState = {
options: {
useMargins: true,
syncColors: false,
syncCursor: true,
syncTooltips: false,
hidePanelTitles: false,
},

View file

@ -71,6 +71,7 @@ export interface DashboardContainerInput extends ContainerInput {
useMargins: boolean;
syncColors?: boolean;
syncTooltips?: boolean;
syncCursor?: boolean;
viewMode: ViewMode;
filters: Filter[];
title: string;
@ -118,6 +119,7 @@ export type DashboardOptions = {
hidePanelTitles: boolean;
useMargins: boolean;
syncColors: boolean;
syncCursor: boolean;
syncTooltips: boolean;
};

View file

@ -58,6 +58,11 @@ export type EmbeddableInput = {
*/
syncColors?: boolean;
/**
* Flag whether cursor should be synced with other panels on hover
*/
syncCursor?: boolean;
/**
* Flag whether tooltips should be synced with other panels on hover
*/

View file

@ -21,6 +21,7 @@ const getGenericEmbeddableState = (state?: Partial<EmbeddableInput>): Embeddable
enhancements: undefined,
syncColors: false,
syncTooltips: false,
syncCursor: true,
viewMode: ViewMode.VIEW,
title: 'So Very Generic',
id: 'soVeryGeneric',
@ -46,6 +47,7 @@ test('Omitting generic embeddable input omits all generic input keys', () => {
'enhancements',
'syncColors',
'syncTooltips',
'syncCursor',
'viewMode',
'title',
'id',

View file

@ -20,6 +20,7 @@ const allGenericInputKeys: Readonly<Array<keyof EmbeddableInput>> = [
'disableTriggers',
'enhancements',
'syncColors',
'syncCursor',
'syncTooltips',
'viewMode',
'title',
@ -32,6 +33,7 @@ const genericInputKeysToCompare = [
'disableTriggers',
'enhancements',
'syncColors',
'syncCursor',
'syncTooltips',
'title',
'id',

View file

@ -40,6 +40,9 @@ export const input = createSlice({
setSyncColors(state, action: PayloadAction<EmbeddableInput['syncColors']>) {
state.syncColors = action.payload;
},
setSyncCursor(state, action: PayloadAction<EmbeddableInput['syncCursor']>) {
state.syncCursor = action.payload;
},
setSyncTooltips(state, action: PayloadAction<EmbeddableInput['syncTooltips']>) {
state.syncTooltips = action.payload;
},

View file

@ -225,6 +225,7 @@ export class Execution<
inspectorAdapters.tables[name] = datatable;
},
isSyncColorsEnabled: () => execution.params.syncColors!,
isSyncCursorEnabled: () => execution.params.syncCursor!,
isSyncTooltipsEnabled: () => execution.params.syncTooltips!,
...execution.executor.context,
getExecutionContext: () => execution.params.executionContext,

View file

@ -65,6 +65,11 @@ export interface ExecutionContext<
*/
isSyncColorsEnabled?: () => boolean;
/**
* Returns the state (true|false) of the sync cursor across panels switch.
*/
isSyncCursorEnabled?: () => boolean;
/**
* Returns the state (true|false) of the sync tooltips across panels switch.
*/

View file

@ -93,6 +93,8 @@ export interface IInterpreterRenderHandlers {
isSyncColorsEnabled(): boolean;
isSyncCursorEnabled(): boolean;
isSyncTooltipsEnabled(): boolean;
/**
* This uiState interface is actually `PersistedState` from the visualizations plugin,

View file

@ -152,6 +152,8 @@ export interface ExpressionExecutionParams {
syncColors?: boolean;
syncCursor?: boolean;
syncTooltips?: boolean;
inspectorAdapters?: Adapters;

View file

@ -114,6 +114,7 @@ export class ExpressionLoader {
renderMode: params?.renderMode,
syncColors: params?.syncColors,
syncTooltips: params?.syncTooltips,
syncCursor: params?.syncCursor,
hasCompatibleActions: params?.hasCompatibleActions,
executionContext: params?.executionContext,
});
@ -199,6 +200,7 @@ export class ExpressionLoader {
searchSessionId: params.searchSessionId,
debug: params.debug,
syncColors: params.syncColors,
syncCursor: params?.syncCursor,
syncTooltips: params.syncTooltips,
executionContext: params.executionContext,
});
@ -238,6 +240,7 @@ export class ExpressionLoader {
this.params.searchSessionId = params.searchSessionId;
}
this.params.syncColors = params.syncColors;
this.params.syncCursor = params.syncCursor;
this.params.syncTooltips = params.syncTooltips;
this.params.debug = Boolean(params.debug);
this.params.partial = Boolean(params.partial);

View file

@ -116,6 +116,7 @@ export function useExpressionRenderer(
debouncedLoaderParams.renderMode,
debouncedLoaderParams.syncColors,
debouncedLoaderParams.syncTooltips,
debouncedLoaderParams.syncCursor,
]);
useEffect(() => {

View file

@ -30,6 +30,7 @@ export interface ExpressionRenderHandlerParams {
onRenderError?: RenderErrorHandlerFnType;
renderMode?: RenderMode;
syncColors?: boolean;
syncCursor?: boolean;
syncTooltips?: boolean;
interactive?: boolean;
hasCompatibleActions?: (event: ExpressionRendererEvent) => Promise<boolean>;
@ -59,6 +60,7 @@ export class ExpressionRenderHandler {
renderMode,
syncColors,
syncTooltips,
syncCursor,
interactive,
hasCompatibleActions = async () => false,
executionContext,
@ -106,6 +108,9 @@ export class ExpressionRenderHandler {
isSyncTooltipsEnabled: () => {
return syncTooltips || false;
},
isSyncCursorEnabled: () => {
return syncCursor || true;
},
isInteractive: () => {
return interactive ?? true;
},

View file

@ -50,6 +50,7 @@ export interface IExpressionLoaderParams {
searchSessionId?: string;
renderMode?: RenderMode;
syncColors?: boolean;
syncCursor?: boolean;
syncTooltips?: boolean;
hasCompatibleActions?: ExpressionRenderHandlerParams['hasCompatibleActions'];
executionContext?: KibanaExecutionContext;

View file

@ -16,6 +16,7 @@ import {
export const defaultHandlers: IInterpreterRenderHandlers = {
getRenderMode: () => 'view',
isSyncColorsEnabled: () => false,
isSyncCursorEnabled: () => true,
isSyncTooltipsEnabled: () => false,
isInteractive: () => true,
getExecutionContext: () => undefined,

View file

@ -59,6 +59,7 @@ interface TimelionVisComponentProps {
renderComplete: IInterpreterRenderHandlers['done'];
ariaLabel?: string;
syncTooltips?: boolean;
syncCursor?: boolean;
}
const DefaultYAxis = () => (
@ -104,6 +105,7 @@ export const TimelionVisComponent = ({
onBrushEvent,
ariaLabel,
syncTooltips,
syncCursor,
}: TimelionVisComponentProps) => {
const kibana = useKibana<TimelionVisDependencies>();
const chartRef = useRef<Chart>(null);
@ -203,7 +205,7 @@ export const TimelionVisComponent = ({
showLegendExtra={true}
legendPosition={legend.legendPosition}
onRenderChange={onRenderChange}
onPointerUpdate={handleCursorUpdate}
onPointerUpdate={syncCursor ? handleCursorUpdate : undefined}
externalPointerEvents={{
tooltip: { visible: syncTooltips, placement: Placement.Right },
}}

View file

@ -22,6 +22,7 @@ export interface TimelionRenderValue {
visType: 'timelion';
visParams: TimelionVisParams;
syncTooltips: boolean;
syncCursor: boolean;
}
export interface TimelionVisParams {
@ -75,6 +76,7 @@ export const getTimelionVisualizationConfig = (
variables,
abortSignal: expressionAbortSignal,
isSyncTooltipsEnabled,
isSyncCursorEnabled,
}
) {
const { getTimelionRequestHandler } = await import('./async_services');
@ -114,6 +116,7 @@ export const getTimelionVisualizationConfig = (
visType: TIMELION_VIS_NAME,
visData,
syncTooltips: isSyncTooltipsEnabled?.() ?? false,
syncCursor: isSyncTooltipsEnabled?.() ?? true,
},
};
},

View file

@ -43,7 +43,7 @@ export const getTimelionVisRenderer: (
name: 'timelion_vis',
displayName: 'Timelion visualization',
reuseDomNode: true,
render: (domNode, { visData, visParams, syncTooltips }, handlers) => {
render: (domNode, { visData, visParams, syncTooltips, syncCursor }, handlers) => {
handlers.onDestroy(() => {
unmountComponentAtNode(domNode);
});
@ -99,6 +99,7 @@ export const getTimelionVisRenderer: (
renderComplete={renderComplete}
onBrushEvent={onBrushEvent}
syncTooltips={syncTooltips}
syncCursor={syncCursor}
/>
)}
</KibanaContextProvider>

View file

@ -37,6 +37,7 @@ interface TimeseriesVisualizationProps {
visData: TimeseriesVisData;
uiState: PersistedState;
syncColors: boolean;
syncCursor: boolean;
syncTooltips: boolean;
initialRender: () => void;
}
@ -48,6 +49,7 @@ function TimeseriesVisualization({
uiState,
getConfig,
syncColors,
syncCursor,
syncTooltips,
initialRender,
}: TimeseriesVisualizationProps) {
@ -194,6 +196,7 @@ function TimeseriesVisualization({
onUiState={handleUiState}
syncColors={syncColors}
syncTooltips={syncTooltips}
syncCursor={syncCursor}
palettesService={palettesService}
indexPattern={indexPattern}
fieldFormatMap={indexPattern?.fieldFormatMap}

View file

@ -64,6 +64,7 @@ export interface TimeseriesVisProps {
getConfig: IUiSettingsClient['get'];
syncColors: boolean;
syncTooltips: boolean;
syncCursor: boolean;
palettesService: PaletteRegistry;
indexPattern?: FetchedIndexPattern['indexPattern'];
/** @deprecated please use indexPattern.fieldFormatMap instead **/

View file

@ -163,6 +163,7 @@ class TimeseriesVisualization extends Component {
onFilterClick,
syncColors,
syncTooltips,
syncCursor,
palettesService,
fieldFormatMap,
getConfig,
@ -275,6 +276,7 @@ class TimeseriesVisualization extends Component {
annotations={this.prepareAnnotations()}
syncColors={syncColors}
syncTooltips={syncTooltips}
syncCursor={syncCursor}
palettesService={palettesService}
interval={interval}
initialRender={initialRender}

View file

@ -73,6 +73,7 @@ export const TimeSeries = ({
annotations,
syncColors,
syncTooltips,
syncCursor,
palettesService,
interval,
isLastBucketDropped,
@ -179,7 +180,7 @@ export const TimeSeries = ({
onBrushEnd={onBrushEndListener}
onElementClick={(args) => handleElementClick(args)}
animateData={false}
onPointerUpdate={handleCursorUpdate}
onPointerUpdate={syncCursor ? handleCursorUpdate : undefined}
pointerUpdateDebounce={0}
theme={[
{

View file

@ -26,6 +26,7 @@ export interface TimeseriesRenderValue {
visData: TimeseriesVisData | {};
visParams: TimeseriesVisParams;
syncColors: boolean;
syncCursor: boolean;
syncTooltips: boolean;
canNavigateToLens?: boolean;
}
@ -63,6 +64,7 @@ export const createMetricsFn = (): TimeseriesExpressionFunctionDefinition => ({
getSearchSessionId,
isSyncColorsEnabled,
isSyncTooltipsEnabled,
isSyncCursorEnabled,
getExecutionContext,
inspectorAdapters,
abortSignal: expressionAbortSignal,
@ -73,6 +75,7 @@ export const createMetricsFn = (): TimeseriesExpressionFunctionDefinition => ({
const uiState = JSON.parse(args.uiState);
const syncColors = isSyncColorsEnabled?.() ?? false;
const syncTooltips = isSyncTooltipsEnabled?.() ?? false;
const syncCursor = isSyncCursorEnabled?.() ?? true;
const response = await metricsRequestHandler({
input,
@ -92,6 +95,7 @@ export const createMetricsFn = (): TimeseriesExpressionFunctionDefinition => ({
visData: response,
syncColors,
syncTooltips,
syncCursor,
canNavigateToLens: variables.canNavigateToLens as boolean,
},
};

View file

@ -62,7 +62,14 @@ export const getTimeseriesVisRenderer: (deps: {
handlers.onDestroy(() => {
unmountComponentAtNode(domNode);
});
const { visParams: model, visData, syncColors, syncTooltips, canNavigateToLens } = config;
const {
visParams: model,
visData,
syncColors,
syncTooltips,
syncCursor,
canNavigateToLens,
} = config;
const showNoResult = !checkIfDataExists(visData, model);
const renderComplete = () => {
@ -106,6 +113,7 @@ export const getTimeseriesVisRenderer: (deps: {
visData={visData as TimeseriesVisData}
syncColors={syncColors}
syncTooltips={syncTooltips}
syncCursor={syncCursor}
uiState={handlers.uiState! as PersistedState}
initialRender={renderComplete}
/>

View file

@ -110,6 +110,7 @@ export class VisualizeEmbeddable
private searchSessionId?: string;
private syncColors?: boolean;
private syncTooltips?: boolean;
private syncCursor?: boolean;
private embeddableTitle?: string;
private visCustomizations?: Pick<VisualizeInput, 'vis' | 'table'>;
private subscriptions: Subscription[] = [];
@ -154,6 +155,7 @@ export class VisualizeEmbeddable
this.timefilter = timefilter;
this.syncColors = this.input.syncColors;
this.syncTooltips = this.input.syncTooltips;
this.syncCursor = this.input.syncCursor;
this.searchSessionId = this.input.searchSessionId;
this.query = this.input.query;
this.embeddableTitle = this.getTitle();
@ -322,6 +324,11 @@ export class VisualizeEmbeddable
dirty = true;
}
if (this.syncCursor !== this.input.syncCursor) {
this.syncCursor = this.input.syncCursor;
dirty = true;
}
if (this.embeddableTitle !== this.getTitle()) {
this.embeddableTitle = this.getTitle();
dirty = true;
@ -574,6 +581,7 @@ export class VisualizeEmbeddable
searchSessionId: this.input.searchSessionId,
syncColors: this.input.syncColors,
syncTooltips: this.input.syncTooltips,
syncCursor: this.input.syncCursor,
uiState: this.vis.uiState,
interactive: !this.input.disableTriggers,
inspectorAdapters: this.inspectorAdapters,

View file

@ -15,6 +15,7 @@ export const defaultHandlers: RendererHandlers = {
getFilter: () => 'filter',
getRenderMode: () => 'view',
isSyncColorsEnabled: () => false,
isSyncCursorEnabled: () => true,
isSyncTooltipsEnabled: () => false,
isInteractive: () => true,
onComplete: (fn) => undefined,

View file

@ -28,6 +28,7 @@ export const createBaseHandlers = (): IInterpreterRenderHandlers => ({
getRenderMode: () => 'view',
isSyncColorsEnabled: () => false,
isSyncTooltipsEnabled: () => false,
isSyncCursorEnabled: () => true,
isInteractive: () => true,
getExecutionContext: () => undefined,
});

View file

@ -677,6 +677,7 @@ export class Embeddable
renderMode={input.renderMode}
syncColors={input.syncColors}
syncTooltips={input.syncTooltips}
syncCursor={input.syncCursor}
hasCompatibleActions={this.hasCompatibleActions}
className={input.className}
style={input.style}

View file

@ -39,6 +39,7 @@ export interface ExpressionWrapperProps {
renderMode?: RenderMode;
syncColors?: boolean;
syncTooltips?: boolean;
syncCursor?: boolean;
hasCompatibleActions?: ReactExpressionRendererProps['hasCompatibleActions'];
style?: React.CSSProperties;
className?: string;
@ -113,6 +114,7 @@ export function ExpressionWrapper({
renderMode,
syncColors,
syncTooltips,
syncCursor,
hasCompatibleActions,
style,
className,
@ -143,6 +145,7 @@ export function ExpressionWrapper({
renderMode={renderMode}
syncColors={syncColors}
syncTooltips={syncTooltips}
syncCursor={syncCursor}
executionContext={executionContext}
renderError={(errorMessage, error) => {
onRuntimeError();