mirror of
https://github.com/elastic/kibana.git
synced 2025-04-25 02:09:32 -04:00
[Profiling][Flamegraps] persistent normalization mode (#153116)
https://user-images.githubusercontent.com/55978943/224367585-a6623d40-951b-418a-8615-2c3de46e4e6e.mov Saves the normalization option selected and keeps it when changing the comparison mode. I also refactored the Flamegraph component extracting some components away to simplify.
This commit is contained in:
parent
6552165c57
commit
58c918a061
3 changed files with 198 additions and 151 deletions
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
import { EuiButtonGroup, EuiFlexGroup, EuiFlexItem, EuiTitle } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import React from 'react';
|
||||
import { FlameGraphComparisonMode } from '../../../common/flamegraph';
|
||||
|
||||
interface Props {
|
||||
comparisonMode: FlameGraphComparisonMode;
|
||||
onChange: (nextComparisonMode: FlameGraphComparisonMode) => void;
|
||||
}
|
||||
export function DifferentialComparisonMode({ comparisonMode, onChange }: Props) {
|
||||
return (
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiFlexGroup direction="row" gutterSize="m" alignItems="center">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiTitle size="xxs">
|
||||
<h3>
|
||||
{i18n.translate(
|
||||
'xpack.profiling.flameGraphsView.differentialFlameGraphComparisonModeTitle',
|
||||
{ defaultMessage: 'Format' }
|
||||
)}
|
||||
</h3>
|
||||
</EuiTitle>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButtonGroup
|
||||
legend={i18n.translate(
|
||||
'xpack.profiling.flameGraphsView.differentialFlameGraphComparisonModeLegend',
|
||||
{
|
||||
defaultMessage:
|
||||
'This switch allows you to switch between an absolute and relative comparison between both graphs',
|
||||
}
|
||||
)}
|
||||
type="single"
|
||||
buttonSize="s"
|
||||
idSelected={comparisonMode}
|
||||
onChange={(nextComparisonMode) => {
|
||||
onChange(nextComparisonMode as FlameGraphComparisonMode);
|
||||
}}
|
||||
options={[
|
||||
{
|
||||
id: FlameGraphComparisonMode.Absolute,
|
||||
label: i18n.translate(
|
||||
'xpack.profiling.flameGraphsView.differentialFlameGraphComparisonModeAbsoluteButtonLabel',
|
||||
{
|
||||
defaultMessage: 'Abs',
|
||||
}
|
||||
),
|
||||
},
|
||||
{
|
||||
id: FlameGraphComparisonMode.Relative,
|
||||
label: i18n.translate(
|
||||
'xpack.profiling.flameGraphsView.differentialFlameGraphComparisonModeRelativeButtonLabel',
|
||||
{
|
||||
defaultMessage: 'Rel',
|
||||
}
|
||||
),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
import { EuiFlexGroup, EuiFlexItem, EuiHorizontalRule, EuiPanel } from '@elastic/eui';
|
||||
import React from 'react';
|
||||
import { FlameGraphInformationWindowSwitch } from '.';
|
||||
import { FlameGraphComparisonMode, FlameGraphNormalizationMode } from '../../../common/flamegraph';
|
||||
import { useProfilingParams } from '../../hooks/use_profiling_params';
|
||||
import { useProfilingRouter } from '../../hooks/use_profiling_router';
|
||||
import { useProfilingRoutePath } from '../../hooks/use_profiling_route_path';
|
||||
import { PrimaryAndComparisonSearchBar } from '../primary_and_comparison_search_bar';
|
||||
import { PrimaryProfilingSearchBar } from '../profiling_app_page_template/primary_profiling_search_bar';
|
||||
import { DifferentialComparisonMode } from './differential_comparison_mode';
|
||||
import { FlameGraphNormalizationOptions, NormalizationMenu } from './normalization_menu';
|
||||
|
||||
interface Props {
|
||||
isDifferentialView: boolean;
|
||||
comparisonMode: FlameGraphComparisonMode;
|
||||
normalizationMode: FlameGraphNormalizationMode;
|
||||
normalizationOptions: FlameGraphNormalizationOptions;
|
||||
showInformationWindow: boolean;
|
||||
onChangeShowInformationWindow: () => void;
|
||||
}
|
||||
|
||||
export function FlameGraphSearchPanel({
|
||||
comparisonMode,
|
||||
normalizationMode,
|
||||
isDifferentialView,
|
||||
normalizationOptions,
|
||||
showInformationWindow,
|
||||
onChangeShowInformationWindow,
|
||||
}: Props) {
|
||||
const { path, query } = useProfilingParams('/flamegraphs/*');
|
||||
const routePath = useProfilingRoutePath();
|
||||
const profilingRouter = useProfilingRouter();
|
||||
|
||||
function onChangeComparisonMode(nextComparisonMode: FlameGraphComparisonMode) {
|
||||
if (!('comparisonRangeFrom' in query)) {
|
||||
return;
|
||||
}
|
||||
|
||||
profilingRouter.push(routePath, {
|
||||
path,
|
||||
query: {
|
||||
...query,
|
||||
...(nextComparisonMode === FlameGraphComparisonMode.Absolute
|
||||
? {
|
||||
comparisonMode: FlameGraphComparisonMode.Absolute,
|
||||
normalizationMode,
|
||||
}
|
||||
: { comparisonMode: FlameGraphComparisonMode.Relative }),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function onChangeNormalizationMode(
|
||||
nextNormalizationMode: FlameGraphNormalizationMode,
|
||||
options: FlameGraphNormalizationOptions
|
||||
) {
|
||||
profilingRouter.push(routePath, {
|
||||
path: routePath,
|
||||
query:
|
||||
nextNormalizationMode === FlameGraphNormalizationMode.Scale
|
||||
? {
|
||||
...query,
|
||||
baseline: options.baselineScale,
|
||||
comparison: options.comparisonScale,
|
||||
normalizationMode: nextNormalizationMode,
|
||||
}
|
||||
: {
|
||||
...query,
|
||||
normalizationMode: nextNormalizationMode,
|
||||
},
|
||||
});
|
||||
}
|
||||
return (
|
||||
<EuiPanel hasShadow={false} color="subdued">
|
||||
{isDifferentialView ? <PrimaryAndComparisonSearchBar /> : <PrimaryProfilingSearchBar />}
|
||||
<EuiHorizontalRule />
|
||||
<EuiFlexGroup direction="row">
|
||||
{isDifferentialView && (
|
||||
<>
|
||||
<DifferentialComparisonMode
|
||||
comparisonMode={comparisonMode}
|
||||
onChange={onChangeComparisonMode}
|
||||
/>
|
||||
{comparisonMode === FlameGraphComparisonMode.Absolute && (
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiFlexGroup direction="row" gutterSize="m" alignItems="center">
|
||||
<EuiFlexItem grow={false}>
|
||||
<NormalizationMenu
|
||||
onChange={onChangeNormalizationMode}
|
||||
mode={normalizationMode}
|
||||
options={normalizationOptions}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
<EuiFlexItem grow style={{ alignItems: 'flex-end' }}>
|
||||
<FlameGraphInformationWindowSwitch
|
||||
showInformationWindow={showInformationWindow}
|
||||
onChange={onChangeShowInformationWindow}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiPanel>
|
||||
);
|
||||
}
|
|
@ -4,16 +4,7 @@
|
|||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
import {
|
||||
EuiButtonGroup,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiHorizontalRule,
|
||||
EuiPageHeaderContentProps,
|
||||
EuiPanel,
|
||||
EuiSwitch,
|
||||
EuiTitle,
|
||||
} from '@elastic/eui';
|
||||
import { EuiFlexGroup, EuiFlexItem, EuiPageHeaderContentProps, EuiSwitch } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { get } from 'lodash';
|
||||
import React, { useState } from 'react';
|
||||
|
@ -26,11 +17,10 @@ import { useTimeRangeAsync } from '../../hooks/use_time_range_async';
|
|||
import { AsyncComponent } from '../async_component';
|
||||
import { useProfilingDependencies } from '../contexts/profiling_dependencies/use_profiling_dependencies';
|
||||
import { FlameGraph } from '../flamegraph';
|
||||
import { PrimaryAndComparisonSearchBar } from '../primary_and_comparison_search_bar';
|
||||
import { PrimaryProfilingSearchBar } from '../profiling_app_page_template/primary_profiling_search_bar';
|
||||
import { ProfilingAppPageTemplate } from '../profiling_app_page_template';
|
||||
import { RedirectTo } from '../redirect_to';
|
||||
import { FlameGraphNormalizationOptions, NormalizationMenu } from './normalization_menu';
|
||||
import { FlameGraphSearchPanel } from './flame_graph_search_panel';
|
||||
import { FlameGraphNormalizationOptions } from './normalization_menu';
|
||||
|
||||
export function FlameGraphInformationWindowSwitch({
|
||||
showInformationWindow,
|
||||
|
@ -50,25 +40,8 @@ export function FlameGraphInformationWindowSwitch({
|
|||
);
|
||||
}
|
||||
|
||||
export function FlameGraphSearchPanel({
|
||||
children,
|
||||
searchBar,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
searchBar: JSX.Element;
|
||||
}) {
|
||||
return (
|
||||
<EuiPanel hasShadow={false} color="subdued">
|
||||
{searchBar}
|
||||
<EuiHorizontalRule />
|
||||
<EuiFlexGroup direction="row">{children}</EuiFlexGroup>
|
||||
</EuiPanel>
|
||||
);
|
||||
}
|
||||
|
||||
export function FlameGraphsView({ children }: { children: React.ReactElement }) {
|
||||
const {
|
||||
path,
|
||||
query,
|
||||
query: { rangeFrom, rangeTo, kuery },
|
||||
} = useProfilingParams('/flamegraphs/*');
|
||||
|
@ -184,136 +157,26 @@ export function FlameGraphsView({ children }: { children: React.ReactElement })
|
|||
];
|
||||
|
||||
const [showInformationWindow, setShowInformationWindow] = useState(false);
|
||||
function toggleShowInformationWindow() {
|
||||
setShowInformationWindow((prev) => !prev);
|
||||
}
|
||||
|
||||
if (routePath === '/flamegraphs') {
|
||||
return <RedirectTo pathname="/flamegraphs/flamegraph" />;
|
||||
}
|
||||
|
||||
const searchBar = isDifferentialView ? (
|
||||
<PrimaryAndComparisonSearchBar />
|
||||
) : (
|
||||
<PrimaryProfilingSearchBar />
|
||||
);
|
||||
|
||||
const differentialComparisonMode = (
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiFlexGroup direction="row" gutterSize="m" alignItems="center">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiTitle size="xxs">
|
||||
<h3>
|
||||
{i18n.translate(
|
||||
'xpack.profiling.flameGraphsView.differentialFlameGraphComparisonModeTitle',
|
||||
{ defaultMessage: 'Format' }
|
||||
)}
|
||||
</h3>
|
||||
</EuiTitle>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButtonGroup
|
||||
legend={i18n.translate(
|
||||
'xpack.profiling.flameGraphsView.differentialFlameGraphComparisonModeLegend',
|
||||
{
|
||||
defaultMessage:
|
||||
'This switch allows you to switch between an absolute and relative comparison between both graphs',
|
||||
}
|
||||
)}
|
||||
type="single"
|
||||
buttonSize="s"
|
||||
idSelected={comparisonMode}
|
||||
onChange={(nextComparisonMode) => {
|
||||
if (!('comparisonRangeFrom' in query)) {
|
||||
return;
|
||||
}
|
||||
|
||||
profilingRouter.push(routePath, {
|
||||
path,
|
||||
query: {
|
||||
...query,
|
||||
...(nextComparisonMode === FlameGraphComparisonMode.Absolute
|
||||
? {
|
||||
comparisonMode: FlameGraphComparisonMode.Absolute,
|
||||
normalizationMode: FlameGraphNormalizationMode.Time,
|
||||
}
|
||||
: { comparisonMode: FlameGraphComparisonMode.Relative }),
|
||||
},
|
||||
});
|
||||
}}
|
||||
options={[
|
||||
{
|
||||
id: FlameGraphComparisonMode.Absolute,
|
||||
label: i18n.translate(
|
||||
'xpack.profiling.flameGraphsView.differentialFlameGraphComparisonModeAbsoluteButtonLabel',
|
||||
{
|
||||
defaultMessage: 'Abs',
|
||||
}
|
||||
),
|
||||
},
|
||||
{
|
||||
id: FlameGraphComparisonMode.Relative,
|
||||
label: i18n.translate(
|
||||
'xpack.profiling.flameGraphsView.differentialFlameGraphComparisonModeRelativeButtonLabel',
|
||||
{
|
||||
defaultMessage: 'Rel',
|
||||
}
|
||||
),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
);
|
||||
|
||||
const differentialComparisonNormalization = (
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiFlexGroup direction="row" gutterSize="m" alignItems="center">
|
||||
<EuiFlexItem grow={false}>
|
||||
<NormalizationMenu
|
||||
onChange={(mode, options) => {
|
||||
profilingRouter.push(routePath, {
|
||||
path: routePath,
|
||||
query:
|
||||
mode === FlameGraphNormalizationMode.Scale
|
||||
? {
|
||||
...query,
|
||||
baseline: options.baselineScale,
|
||||
comparison: options.comparisonScale,
|
||||
normalizationMode: mode,
|
||||
}
|
||||
: {
|
||||
...query,
|
||||
normalizationMode: mode,
|
||||
},
|
||||
});
|
||||
}}
|
||||
mode={normalizationMode}
|
||||
options={normalizationOptions}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
);
|
||||
|
||||
const informationWindowSwitch = (
|
||||
<EuiFlexItem grow style={{ alignItems: 'flex-end' }}>
|
||||
<FlameGraphInformationWindowSwitch
|
||||
showInformationWindow={showInformationWindow}
|
||||
onChange={() => setShowInformationWindow((prev) => !prev)}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
);
|
||||
|
||||
return (
|
||||
<ProfilingAppPageTemplate tabs={tabs} hideSearchBar={true}>
|
||||
<EuiFlexGroup direction="column">
|
||||
<EuiFlexItem grow={false}>
|
||||
<FlameGraphSearchPanel searchBar={searchBar}>
|
||||
{isDifferentialView && differentialComparisonMode}
|
||||
{isDifferentialView &&
|
||||
comparisonMode === FlameGraphComparisonMode.Absolute &&
|
||||
differentialComparisonNormalization}
|
||||
{informationWindowSwitch}
|
||||
</FlameGraphSearchPanel>
|
||||
<FlameGraphSearchPanel
|
||||
isDifferentialView={isDifferentialView}
|
||||
comparisonMode={comparisonMode}
|
||||
normalizationMode={normalizationMode}
|
||||
normalizationOptions={normalizationOptions}
|
||||
showInformationWindow={showInformationWindow}
|
||||
onChangeShowInformationWindow={toggleShowInformationWindow}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<AsyncComponent {...state} style={{ height: '100%' }} size="xl">
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue