[Profiling] Restore show information window (#151538)

## Summary

This PR returns the show information window to the flamegraph view.

We also added a minor UI improvement to keep the flamegraph view
visually synced up with the differential flamegraph view.

Fixes https://github.com/elastic/prodfiler/issues/3009

### Screenshots

The "Show information window" toggle is visible and disabled.

![image](https://user-images.githubusercontent.com/6038/219519101-5e8a9797-faa4-4ffe-ab72-1281df7759dc.png)

The "Show information window" toggle is visible and enabled.

![image](https://user-images.githubusercontent.com/6038/219519115-8b9b5539-82f5-4eb9-b667-4b283e6f39d8.png)
This commit is contained in:
Joseph Crail 2023-02-21 16:46:00 -08:00 committed by GitHub
parent 386ec37237
commit 0764bd1b7d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -27,10 +27,45 @@ import { AsyncComponent } from '../async_component';
import { useProfilingDependencies } from '../contexts/profiling_dependencies/use_profiling_dependencies'; import { useProfilingDependencies } from '../contexts/profiling_dependencies/use_profiling_dependencies';
import { FlameGraph } from '../flamegraph'; import { FlameGraph } from '../flamegraph';
import { PrimaryAndComparisonSearchBar } from '../primary_and_comparison_search_bar'; 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 { ProfilingAppPageTemplate } from '../profiling_app_page_template';
import { RedirectTo } from '../redirect_to'; import { RedirectTo } from '../redirect_to';
import { FlameGraphNormalizationOptions, NormalizationMenu } from './normalization_menu'; import { FlameGraphNormalizationOptions, NormalizationMenu } from './normalization_menu';
export function FlameGraphInformationWindowSwitch({
showInformationWindow,
onChange,
}: {
showInformationWindow: boolean;
onChange: () => void;
}) {
return (
<EuiSwitch
checked={showInformationWindow}
onChange={onChange}
label={i18n.translate('xpack.profiling.flameGraph.showInformationWindow', {
defaultMessage: 'Show information window',
})}
/>
);
}
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 }) { export function FlameGraphsView({ children }: { children: React.ReactElement }) {
const { const {
path, path,
@ -132,136 +167,140 @@ export function FlameGraphsView({ children }: { children: React.ReactElement })
return <RedirectTo pathname="/flamegraphs/flamegraph" />; return <RedirectTo pathname="/flamegraphs/flamegraph" />;
} }
return ( const searchBar = isDifferentialView ? (
<ProfilingAppPageTemplate tabs={tabs} hideSearchBar={isDifferentialView}> <PrimaryAndComparisonSearchBar />
<EuiFlexGroup direction="column"> ) : (
{isDifferentialView ? ( <PrimaryProfilingSearchBar />
<EuiFlexItem grow={false}> );
<EuiPanel hasShadow={false} color="subdued">
<PrimaryAndComparisonSearchBar />
<EuiHorizontalRule />
<EuiFlexGroup direction="row">
<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, { const differentialComparisonMode = (
path, <EuiFlexItem grow={false}>
query: { <EuiFlexGroup direction="row" gutterSize="m" alignItems="center">
...query, <EuiFlexItem grow={false}>
...(nextComparisonMode === FlameGraphComparisonMode.Absolute <EuiTitle size="xxs">
? { <h3>
comparisonMode: FlameGraphComparisonMode.Absolute, {i18n.translate(
normalizationMode: FlameGraphNormalizationMode.Time, 'xpack.profiling.flameGraphsView.differentialFlameGraphComparisonModeTitle',
} { defaultMessage: 'Format' }
: { comparisonMode: FlameGraphComparisonMode.Relative }), )}
}, </h3>
}); </EuiTitle>
}} </EuiFlexItem>
options={[ <EuiFlexItem grow={false}>
{ <EuiButtonGroup
id: FlameGraphComparisonMode.Absolute, legend={i18n.translate(
label: i18n.translate( 'xpack.profiling.flameGraphsView.differentialFlameGraphComparisonModeLegend',
'xpack.profiling.flameGraphsView.differentialFlameGraphComparisonModeAbsoluteButtonLabel', {
{ defaultMessage:
defaultMessage: 'Abs', 'This switch allows you to switch between an absolute and relative comparison between both graphs',
} }
), )}
}, type="single"
{ buttonSize="s"
id: FlameGraphComparisonMode.Relative, idSelected={comparisonMode}
label: i18n.translate( onChange={(nextComparisonMode) => {
'xpack.profiling.flameGraphsView.differentialFlameGraphComparisonModeRelativeButtonLabel', if (!('comparisonRangeFrom' in query)) {
{ return;
defaultMessage: 'Rel', }
}
), profilingRouter.push(routePath, {
}, path,
]} query: {
/> ...query,
</EuiFlexItem> ...(nextComparisonMode === FlameGraphComparisonMode.Absolute
</EuiFlexGroup> ? {
</EuiFlexItem> comparisonMode: FlameGraphComparisonMode.Absolute,
{comparisonMode === FlameGraphComparisonMode.Absolute ? ( normalizationMode: FlameGraphNormalizationMode.Time,
<EuiFlexItem grow={false}> }
<EuiFlexGroup direction="row" gutterSize="m" alignItems="center"> : { comparisonMode: FlameGraphComparisonMode.Relative }),
<EuiFlexItem grow={false}> },
<NormalizationMenu });
onChange={(options) => { }}
profilingRouter.push(routePath, { options={[
path: routePath, {
// @ts-expect-error Code gets too complicated to satisfy TS constraints id: FlameGraphComparisonMode.Absolute,
query: { label: i18n.translate(
...query, 'xpack.profiling.flameGraphsView.differentialFlameGraphComparisonModeAbsoluteButtonLabel',
...pick(options, 'baseline', 'comparison'), {
normalizationMode: options.mode, defaultMessage: 'Abs',
}, }
}); ),
}} },
totalSeconds={ {
(new Date(timeRange.end).getTime() - id: FlameGraphComparisonMode.Relative,
new Date(timeRange.start).getTime()) / label: i18n.translate(
1000 'xpack.profiling.flameGraphsView.differentialFlameGraphComparisonModeRelativeButtonLabel',
} {
comparisonTotalSeconds={ defaultMessage: 'Rel',
(new Date(comparisonTimeRange.end!).getTime() - }
new Date(comparisonTimeRange.start!).getTime()) / ),
1000 },
} ]}
options={ />
(normalizationMode === FlameGraphNormalizationMode.Time </EuiFlexItem>
? { mode: FlameGraphNormalizationMode.Time } </EuiFlexGroup>
: { </EuiFlexItem>
mode: FlameGraphNormalizationMode.Scale, );
baseline,
comparison, const differentialComparisonNormalization = (
}) as FlameGraphNormalizationOptions <EuiFlexItem grow={false}>
} <EuiFlexGroup direction="row" gutterSize="m" alignItems="center">
/> <EuiFlexItem grow={false}>
</EuiFlexItem> <NormalizationMenu
</EuiFlexGroup> onChange={(options) => {
</EuiFlexItem> profilingRouter.push(routePath, {
) : undefined} path: routePath,
<EuiFlexItem grow style={{ alignItems: 'flex-end' }}> query: {
<EuiSwitch ...query,
checked={showInformationWindow} ...pick(options, 'baseline', 'comparison'),
onChange={() => { normalizationMode: options.mode,
setShowInformationWindow((prev) => !prev); },
}} });
label={i18n.translate('xpack.profiling.flameGraph.showInformationWindow', { }}
defaultMessage: 'Show information window', totalSeconds={
})} (new Date(timeRange.end).getTime() - new Date(timeRange.start).getTime()) / 1000
/> }
</EuiFlexItem> comparisonTotalSeconds={
</EuiFlexGroup> (new Date(comparisonTimeRange.end!).getTime() -
</EuiPanel> new Date(comparisonTimeRange.start!).getTime()) /
</EuiFlexItem> 1000
) : null} }
options={
(normalizationMode === FlameGraphNormalizationMode.Time
? { mode: FlameGraphNormalizationMode.Time }
: {
mode: FlameGraphNormalizationMode.Scale,
baseline,
comparison,
}) as FlameGraphNormalizationOptions
}
/>
</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>
</EuiFlexItem>
<EuiFlexItem> <EuiFlexItem>
<AsyncComponent {...state} style={{ height: '100%' }} size="xl"> <AsyncComponent {...state} style={{ height: '100%' }} size="xl">
<FlameGraph <FlameGraph