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
1 change: 1 addition & 0 deletions static/app/views/explore/hooks/useMetricOptions.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ describe('useMetricOptions', () => {
dataset: 'tracemetrics',
field: ['metric.name', 'metric.type', 'metric.unit', 'count(metric.name)'],
referrer: 'api.explore.metric-options',
statsPeriod: '3d',
}),
})
);
Expand Down
15 changes: 10 additions & 5 deletions static/app/views/explore/hooks/useMetricOptions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,12 @@ function metricOptionsQueryKey({
query.project = projectIds.map(String);
}

if (search && datetime) {
// If searching we use the full filters in order to not miss the result.
if (datetime) {
Object.entries(normalizeDateTimeParams(datetime)).forEach(([key, value]) => {
if (value !== undefined) {
query[key] = value as string | string[];
}
});
} else {
query.statsPeriod = '24h'; // Default to a much smaller time window if not searching.
}

return [`/organizations/${orgSlug}/events/`, {query}];
Expand Down Expand Up @@ -112,5 +109,13 @@ export function useMetricOptions({
}
}, [result.data]);

return result;
const isMetricOptionsEmpty =
!result.isFetching &&
!result.isLoading &&
(!result.data?.data || result.data.data.length === 0);

return {
...result,
isMetricOptionsEmpty,
};
}
33 changes: 30 additions & 3 deletions static/app/views/explore/metrics/metricGraph/index.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import {Fragment, useMemo} from 'react';

import {ExternalLink} from '@sentry/scraps/link';

import {CompactSelect} from 'sentry/components/core/compactSelect';
import {Tooltip} from 'sentry/components/core/tooltip';
import {IconClock, IconGraph} from 'sentry/icons';
import {t} from 'sentry/locale';
import {t, tct} from 'sentry/locale';
import {defined} from 'sentry/utils';
import {determineSeriesSampleCountAndIsSampled} from 'sentry/views/alerts/rules/metric/utils/determineSeriesSampleCount';
import {Widget} from 'sentry/views/dashboards/widgets/widget/widget';
Expand All @@ -29,6 +31,7 @@ import {
} from 'sentry/views/explore/utils';
import {ChartType} from 'sentry/views/insights/common/components/chart';
import type {useSortedTimeSeries} from 'sentry/views/insights/common/queries/useSortedTimeSeries';
import {GenericWidgetEmptyStateWarning} from 'sentry/views/performance/landing/widgets/components/selectableList';

import {WidgetWrapper} from './styles';

Expand All @@ -41,6 +44,7 @@ interface MetricsGraphProps {
timeseriesResult: ReturnType<typeof useSortedTimeSeries>;
additionalActions?: React.ReactNode;
infoContentHidden?: boolean;
isMetricOptionsEmpty?: boolean;
}

export function MetricsGraph({
Expand All @@ -49,6 +53,7 @@ export function MetricsGraph({
orientation,
additionalActions,
infoContentHidden,
isMetricOptionsEmpty,
}: MetricsGraphProps) {
const visualize = useMetricVisualize();
const setVisualize = useSetMetricVisualize();
Expand All @@ -66,6 +71,7 @@ export function MetricsGraph({
orientation={orientation}
additionalActions={additionalActions}
infoContentHidden={infoContentHidden}
isMetricOptionsEmpty={isMetricOptionsEmpty}
/>
);
}
Expand All @@ -84,6 +90,7 @@ function Graph({
visualize,
infoContentHidden,
additionalActions,
isMetricOptionsEmpty,
}: GraphProps) {
const aggregate = visualize.yAxis;
const topEventsLimit = useQueryParamsTopEventsLimit();
Expand Down Expand Up @@ -156,14 +163,34 @@ function Graph({
</Fragment>
);

const showEmptyState = isMetricOptionsEmpty && visualize.visible;
const showChart = visualize.visible && !isMetricOptionsEmpty;

return (
<WidgetWrapper hideFooterBorder={orientation === 'bottom'}>
<Widget
Title={Title}
Actions={Actions}
Visualization={visualize.visible && <ChartVisualization chartInfo={chartInfo} />}
Visualization={
showEmptyState ? (
<GenericWidgetEmptyStateWarning
message={tct(
'No metrics found for this time period. If this is unexpected, try updating your filters or [link:learn more] about how to use metrics.',
{
link: (
<ExternalLink href="https://docs.sentry.io/product/explore/metrics/">
{t('learn more')}
</ExternalLink>
),
}
)}
/>
) : showChart ? (
<ChartVisualization chartInfo={chartInfo} />
) : undefined
}
Footer={
visualize.visible && (
showChart && (
<ConfidenceFooter
chartInfo={chartInfo}
isLoading={timeseriesResult.isFetching}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import styled from '@emotion/styled';
import throttle from 'lodash/throttle';

import {Tooltip} from 'sentry/components/core/tooltip';
import EmptyStateWarning from 'sentry/components/emptyStateWarning';
import LoadingIndicator from 'sentry/components/loadingIndicator';
import {SimpleTable} from 'sentry/components/tables/simpleTable';
import {IconWarning} from 'sentry/icons/iconWarning';
Expand Down Expand Up @@ -36,19 +35,21 @@ import {
} from 'sentry/views/explore/queryParams/context';
import {FieldRenderer} from 'sentry/views/explore/tables/fieldRenderer';
import {TraceItemDataset} from 'sentry/views/explore/types';
import {GenericWidgetEmptyStateWarning} from 'sentry/views/performance/landing/widgets/components/selectableList';

const RESULT_LIMIT = 50;

interface AggregatesTabProps {
traceMetric: TraceMetric;
isMetricOptionsEmpty?: boolean;
}

export function AggregatesTab({traceMetric}: AggregatesTabProps) {
export function AggregatesTab({traceMetric, isMetricOptionsEmpty}: AggregatesTabProps) {
const topEvents = useTopEvents();
const tableRef = useRef<HTMLDivElement>(null);

const {result, eventView, fields} = useMetricAggregatesTable({
enabled: Boolean(traceMetric.name),
enabled: Boolean(traceMetric.name) && !isMetricOptionsEmpty,
limit: RESULT_LIMIT,
traceMetric,
});
Expand Down Expand Up @@ -151,9 +152,11 @@ export function AggregatesTab({traceMetric}: AggregatesTabProps) {
};
}, [result.data, fields.length]);

const isPending = result.isPending && !isMetricOptionsEmpty;

return (
<StickyCompatibleSimpleTable ref={tableRef} style={tableStyle}>
{result.isPending && <TransparentLoadingMask />}
{isPending && <TransparentLoadingMask />}

<StickyCompatibleStyledHeader>
{fields.map((field, i) => {
Expand Down Expand Up @@ -221,15 +224,13 @@ export function AggregatesTab({traceMetric}: AggregatesTabProps) {
))}
</SimpleTable.Row>
))
) : result.isPending ? (
) : isPending ? (
<SimpleTable.Empty>
<LoadingIndicator />
</SimpleTable.Empty>
) : (
<SimpleTable.Empty>
<EmptyStateWarning>
<p>{t('No aggregates found')}</p>
</EmptyStateWarning>
<GenericWidgetEmptyStateWarning title={t('No aggregates found')} message="" />
</SimpleTable.Empty>
)}
</StickyCompatibleTableBody>
Expand Down
12 changes: 10 additions & 2 deletions static/app/views/explore/metrics/metricInfoTabs/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,15 @@ interface MetricInfoTabsProps {
traceMetric: TraceMetric;
additionalActions?: React.ReactNode;
contentsHidden?: boolean;
isMetricOptionsEmpty?: boolean;
}

export default function MetricInfoTabs({
traceMetric,
additionalActions,
contentsHidden,
orientation,
isMetricOptionsEmpty,
}: MetricInfoTabsProps) {
const visualize = useMetricVisualize();
const queryParamsMode = useQueryParamsMode();
Expand Down Expand Up @@ -61,10 +63,16 @@ export default function MetricInfoTabs({
<BodyContainer>
<StyledTabPanels>
<TabPanels.Item key={Mode.AGGREGATE}>
<AggregatesTab traceMetric={traceMetric} />
<AggregatesTab
traceMetric={traceMetric}
isMetricOptionsEmpty={isMetricOptionsEmpty}
/>
</TabPanels.Item>
<TabPanels.Item key={Mode.SAMPLES}>
<SamplesTab traceMetric={traceMetric} />
<SamplesTab
traceMetric={traceMetric}
isMetricOptionsEmpty={isMetricOptionsEmpty}
/>
</TabPanels.Item>
</StyledTabPanels>
</BodyContainer>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import {useMemo} from 'react';
import styled from '@emotion/styled';

import EmptyStateWarning from 'sentry/components/emptyStateWarning';
import LoadingIndicator from 'sentry/components/loadingIndicator';
import {SimpleTable} from 'sentry/components/tables/simpleTable';
import {IconWarning} from 'sentry/icons';
Expand All @@ -22,6 +21,7 @@ import {SampleTableRow} from 'sentry/views/explore/metrics/metricInfoTabs/metric
import type {TraceMetric} from 'sentry/views/explore/metrics/metricQuery';
import {TraceMetricKnownFieldKey} from 'sentry/views/explore/metrics/types';
import {getMetricTableColumnType} from 'sentry/views/explore/metrics/utils';
import {GenericWidgetEmptyStateWarning} from 'sentry/views/performance/landing/widgets/components/selectableList';

const RESULT_LIMIT = 50;
const TWO_MINUTE_DELAY = 120;
Expand All @@ -31,12 +31,14 @@ export const SAMPLES_PANEL_MIN_WIDTH = 350;

interface MetricsSamplesTableProps {
embedded?: boolean;
isMetricOptionsEmpty?: boolean;
traceMetric?: TraceMetric;
}

export function MetricsSamplesTable({
traceMetric,
embedded = false,
isMetricOptionsEmpty,
}: MetricsSamplesTableProps) {
const columns = embedded ? TraceSamplesTableEmbeddedColumns : TraceSamplesTableColumns;
const fields = columns.filter(c => getMetricTableColumnType(c) !== 'stat');
Expand All @@ -47,7 +49,7 @@ export function MetricsSamplesTable({
error,
isFetching,
} = useMetricSamplesTable({
disabled: embedded ? false : !traceMetric?.name,
disabled: embedded ? false : !traceMetric?.name || isMetricOptionsEmpty,
limit: RESULT_LIMIT,
traceMetric,
fields,
Expand Down Expand Up @@ -92,9 +94,7 @@ export function MetricsSamplesTable({
</SimpleTable.Empty>
) : (
<SimpleTable.Empty>
<EmptyStateWarning>
<p>{t('No samples found')}</p>
</EmptyStateWarning>
<GenericWidgetEmptyStateWarning title={t('No samples found')} message="" />
</SimpleTable.Empty>
)}
</StyledSimpleTableBody>
Expand Down
10 changes: 8 additions & 2 deletions static/app/views/explore/metrics/metricInfoTabs/samplesTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,14 @@ import type {TraceMetric} from 'sentry/views/explore/metrics/metricQuery';

interface SamplesTabProps {
traceMetric: TraceMetric;
isMetricOptionsEmpty?: boolean;
}

export function SamplesTab({traceMetric}: SamplesTabProps) {
return <MetricsSamplesTable traceMetric={traceMetric} />;
export function SamplesTab({traceMetric, isMetricOptionsEmpty}: SamplesTabProps) {
return (
<MetricsSamplesTable
traceMetric={traceMetric}
isMetricOptionsEmpty={isMetricOptionsEmpty}
/>
);
}
10 changes: 7 additions & 3 deletions static/app/views/explore/metrics/metricPanel/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import Panel from 'sentry/components/panels/panel';
import PanelBody from 'sentry/components/panels/panelBody';
import {useMetricsPanelAnalytics} from 'sentry/views/explore/hooks/useAnalytics';
import {useChartInterval} from 'sentry/views/explore/hooks/useChartInterval';
import {useMetricOptions} from 'sentry/views/explore/hooks/useMetricOptions';
import {useTopEvents} from 'sentry/views/explore/hooks/useTopEvents';
import {TraceSamplesTableColumns} from 'sentry/views/explore/metrics/constants';
import {useMetricAggregatesTable} from 'sentry/views/explore/metrics/hooks/useMetricAggregatesTable';
Expand Down Expand Up @@ -35,24 +36,25 @@ export function MetricPanel({traceMetric, queryIndex}: MetricPanelProps) {
canChangeOrientation,
} = useTableOrientationControl();
const [infoContentHidden, setInfoContentHidden] = useState(false);
const {isMetricOptionsEmpty} = useMetricOptions({enabled: Boolean(traceMetric.name)});
const {result: timeseriesResult} = useMetricTimeseries({
traceMetric,
enabled: Boolean(traceMetric.name),
enabled: Boolean(traceMetric.name) && !isMetricOptionsEmpty,
});

const columns = TraceSamplesTableColumns;
const fields = columns.filter(c => getMetricTableColumnType(c) !== 'stat');

const metricSamplesTableResult = useMetricSamplesTable({
disabled: !traceMetric?.name,
disabled: !traceMetric?.name || isMetricOptionsEmpty,
limit: RESULT_LIMIT,
traceMetric,
fields,
ingestionDelaySeconds: TWO_MINUTE_DELAY,
});

const metricAggregatesTableResult = useMetricAggregatesTable({
enabled: Boolean(traceMetric.name),
enabled: Boolean(traceMetric.name) && !isMetricOptionsEmpty,
limit: RESULT_LIMIT,
traceMetric,
});
Expand Down Expand Up @@ -87,6 +89,7 @@ export function MetricPanel({traceMetric, queryIndex}: MetricPanelProps) {
orientation={orientation}
infoContentHidden={infoContentHidden}
setInfoContentHidden={setInfoContentHidden}
isMetricOptionsEmpty={isMetricOptionsEmpty}
/>
) : (
<StackedOrientation
Expand All @@ -98,6 +101,7 @@ export function MetricPanel({traceMetric, queryIndex}: MetricPanelProps) {
canChangeOrientation={canChangeOrientation}
infoContentHidden={infoContentHidden}
setInfoContentHidden={setInfoContentHidden}
isMetricOptionsEmpty={isMetricOptionsEmpty}
/>
)}
</PanelBody>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,10 @@ export function SideBySideOrientation({
setOrientation,
infoContentHidden,
setInfoContentHidden,
isMetricOptionsEmpty,
}: {
infoContentHidden: boolean;
isMetricOptionsEmpty: boolean;
orientation: TableOrientation;
queryIndex: number;
setInfoContentHidden: (hidden: boolean) => void;
Expand Down Expand Up @@ -71,6 +73,7 @@ export function SideBySideOrientation({
orientation={orientation}
additionalActions={additionalActions}
infoContentHidden={infoContentHidden}
isMetricOptionsEmpty={isMetricOptionsEmpty}
/>
</div>
);
Expand All @@ -87,6 +90,7 @@ export function SideBySideOrientation({
timeseriesResult={timeseriesResult}
queryIndex={queryIndex}
orientation={orientation}
isMetricOptionsEmpty={isMetricOptionsEmpty}
/>
),
default: defaultSplit,
Expand All @@ -98,6 +102,7 @@ export function SideBySideOrientation({
traceMetric={traceMetric}
additionalActions={additionalActions}
orientation={orientation}
isMetricOptionsEmpty={isMetricOptionsEmpty}
/>
}
/>
Expand Down
Loading
Loading