Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
137 changes: 137 additions & 0 deletions static/app/views/explore/metrics/confidenceFooter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import styled from '@emotion/styled';

import {Tooltip} from 'sentry/components/core/tooltip';
import Count from 'sentry/components/count';
import {t, tct} from 'sentry/locale';
import type {Confidence} from 'sentry/types/organization';
import {defined} from 'sentry/utils';
import {
Container,
usePreviouslyLoaded,
} from 'sentry/views/explore/components/chart/chartFooter';
import type {ChartInfo} from 'sentry/views/explore/components/chart/types';

interface ConfidenceFooterProps {
chartInfo: ChartInfo;
isLoading: boolean;
}

export function ConfidenceFooter({
chartInfo: currentChartInfo,
isLoading,
}: ConfidenceFooterProps) {
const chartInfo = usePreviouslyLoaded(currentChartInfo, isLoading);

return (
<Container>
<ConfidenceMessage
isLoading={isLoading}
confidence={chartInfo.confidence}
dataScanned={chartInfo.dataScanned}
isSampled={chartInfo.isSampled}
sampleCount={chartInfo.sampleCount}
topEvents={chartInfo.topEvents}
/>
</Container>
);
}

interface ConfidenceMessageProps {
isLoading: boolean;
confidence?: Confidence;
dataScanned?: 'full' | 'partial';
isSampled?: boolean | null;
sampleCount?: number;
topEvents?: number;
}

function ConfidenceMessage({
sampleCount,
dataScanned,
confidence,
topEvents,
isLoading,
isSampled,
}: ConfidenceMessageProps) {
const isTopN = defined(topEvents) && topEvents > 1;

if (!defined(sampleCount) || isLoading) {
return <Placeholder />;
}

const noSampling = defined(isSampled) && !isSampled;
const sampleCountComponent = <Count value={sampleCount} />;

if (dataScanned === 'full') {
// If the full data was scanned, we do not want to expose any
// sample count information because we deem it as unnecessary.
return null;
}

if (confidence === 'low') {
const lowAccuracyFullSampleCount = <LowAccuracyFullTooltip noSampling={noSampling} />;

if (isTopN) {
return tct(
'Top [topEvents] groups extrapolated from [tooltip:[sampleCountComponent] metrics]',
{
topEvents,
tooltip: lowAccuracyFullSampleCount,
sampleCountComponent,
}
);
}

return tct('Extrapolated from [tooltip:[sampleCountComponent] metrics]', {
tooltip: lowAccuracyFullSampleCount,
sampleCountComponent,
});
}

if (isTopN) {
return tct(
'Top [topEvents] groups extrapolated from [sampleCountComponent] metrics',
{
topEvents,
sampleCountComponent,
}
);
}

return tct('Extrapolated from [sampleCountComponent] metrics', {
sampleCountComponent,
});
}

function LowAccuracyFullTooltip({
noSampling,
children,
}: {
noSampling: boolean;
children?: React.ReactNode;
}) {
return (
<Tooltip
title={
<div>
{t('Some metrics are not shown due to the large volume of metrics.')}
<br />
<br />
{t('Try reducing the date range or number of projects.')}
</div>
}
disabled={noSampling}
maxWidth={270}
showUnderline
>
{children}
</Tooltip>
);
}

const Placeholder = styled('div')`
width: 180px;
height: ${p => p.theme.fontSize.md};
border-radius: ${p => p.theme.borderRadius};
background-color: ${p => p.theme.backgroundTertiary};
`;
13 changes: 13 additions & 0 deletions static/app/views/explore/metrics/metricGraph.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {Widget} from 'sentry/views/dashboards/widgets/widget/widget';
import {ChartVisualization} from 'sentry/views/explore/components/chart/chartVisualization';
import {useChartInterval} from 'sentry/views/explore/hooks/useChartInterval';
import {TOP_EVENTS_LIMIT} from 'sentry/views/explore/hooks/useTopEvents';
import {ConfidenceFooter} from 'sentry/views/explore/metrics/confidenceFooter';
import {
useMetricVisualize,
useSetMetricVisualize,
Expand Down Expand Up @@ -123,11 +124,23 @@ function Graph({onChartTypeChange, timeseriesResult, queryIndex, visualize}: Gra
</Fragment>
);

// We explicitly only want to show the confidence footer if we have
// scanned partial data.
const showConfidenceFooter =
chartInfo.dataScanned !== 'full' && !timeseriesResult.isLoading;
return (
<Widget
Title={Title}
Actions={Actions}
Visualization={visualize.visible && <ChartVisualization chartInfo={chartInfo} />}
Footer={
showConfidenceFooter && (
<ConfidenceFooter
chartInfo={chartInfo}
isLoading={timeseriesResult.isLoading}
/>
)
}
revealActions="always"
borderless
/>
Expand Down
Loading