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/router/routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2219,6 +2219,7 @@ function buildRoutes(): RouteObject[] {
index: true,
component: make(() => import('sentry/views/explore/metrics/content')),
},
traceView,
];

const profilingChildren: SentryRouteObject[] = [
Expand Down
7 changes: 7 additions & 0 deletions static/app/views/explore/metrics/constants.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,17 @@ export const TraceSamplesTableEmbeddedColumns: Array<
> = [
VirtualTableSampleColumnKey.EXPAND_ROW,
TraceMetricKnownFieldKey.TIMESTAMP,
VirtualTableSampleColumnKey.PROJECT_BADGE,
TraceMetricKnownFieldKey.METRIC_NAME,
TraceMetricKnownFieldKey.METRIC_TYPE,
TraceMetricKnownFieldKey.METRIC_VALUE,
];

export const NoPaddingColumns: VirtualTableSampleColumnKey[] = [
VirtualTableSampleColumnKey.EXPAND_ROW,
VirtualTableSampleColumnKey.PROJECT_BADGE,
];

export const OPTIONS_BY_TYPE: Record<string, Array<SelectOption<string>>> = {
counter: [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,33 +53,31 @@ export const WrappingText = styled('div')`

export const ExpandedRowContainer = styled('div')<{embedded?: boolean}>`
grid-column: 1 / -1;
border-bottom: 1px solid ${p => p.theme.innerBorder};

${p =>
p.embedded &&
css`
padding: ${p.theme.space.xs} ${p.theme.space.sm};
`}
`;

export const StyledSimpleTableRowCell = styled(SimpleTable.RowCell)<{
embedded?: boolean;
noPadding?: boolean;
}>`
padding: ${p => (p.noPadding ? 0 : p.theme.space.lg)};
padding-top: ${p => (p.noPadding ? 0 : p.theme.space.xs)};
padding-bottom: ${p => (p.noPadding ? 0 : p.theme.space.xs)};
padding: ${p => (p.noPadding ? 0 : p.embedded ? p.theme.space.xl : p.theme.space.lg)};
padding-top: ${p =>
p.noPadding ? 0 : p.embedded ? p.theme.space.sm : p.theme.space.xs};
padding-bottom: ${p =>
p.noPadding ? 0 : p.embedded ? p.theme.space.sm : p.theme.space.xs};

font-size: ${p => p.theme.fontSize.sm};
`;

export const StyledSimpleTableHeaderCell = styled(SimpleTable.HeaderCell)<{
embedded?: boolean;
noPadding?: boolean;
}>`
font-size: ${p => p.theme.fontSize.sm};
padding: ${p => (p.noPadding ? 0 : p.theme.space.lg)};
padding-top: ${p => (p.noPadding ? 0 : p.theme.space.xs)};
padding-bottom: ${p => (p.noPadding ? 0 : p.theme.space.xs)};
padding: ${p => (p.noPadding ? 0 : p.embedded ? p.theme.space.xl : p.theme.space.lg)};
padding-top: ${p =>
p.noPadding ? 0 : p.embedded ? p.theme.space.sm : p.theme.space.xs};
padding-bottom: ${p =>
p.noPadding ? 0 : p.embedded ? p.theme.space.sm : p.theme.space.xs};
`;

export const StyledSimpleTableBody = styled('div')`
Expand Down Expand Up @@ -112,6 +110,8 @@ export const StickyTableRow = styled(SimpleTable.Row)<{
background: ${p.theme.background};
position: sticky;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
margin-right: -15px;
padding-right: calc(15px);
`}
`;

Expand All @@ -124,6 +124,9 @@ export const DetailsContent = styled(StyledPanel)`

export const MetricsDetailsWrapper = styled(DetailsWrapper)`
border-top: 0;
border-bottom: 0;
margin-right: -15px;
padding-right: calc(15px + ${p => p.theme.space.md});
`;

export const NumericSimpleTableHeaderCell = styled(StyledSimpleTableHeaderCell)`
Expand All @@ -144,3 +147,17 @@ export const BodyContainer = styled('div')`
export const StyledTabPanels = styled(TabPanels)`
overflow: auto;
`;

export const TableRowContainer = styled('div')`
display: grid;
grid-template-columns: subgrid;
grid-auto-rows: min-content;
grid-column: 1 / -1;

:not(:last-child) {
border-bottom: 1px solid ${p => p.theme.border};
}

margin-right: -15px;
padding-right: calc(15px);
`;
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export function MetricsSamplesTable({
return (
<SimpleTableWithHiddenColumns numColumns={columns.length - 1} embedded={embedded}>
{isFetching && <TransparentLoadingMask />}
<MetricsSamplesTableHeader columns={columns} />
<MetricsSamplesTableHeader columns={columns} embedded={embedded} />
<StyledSimpleTableBody>
{error ? (
<SimpleTable.Empty>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type {ReactNode} from 'react';
import {Tooltip} from 'sentry/components/core/tooltip';
import {IconFire, IconSpan, IconTerminal} from 'sentry/icons';
import {t} from 'sentry/locale';
import {NoPaddingColumns} from 'sentry/views/explore/metrics/constants';
import {
NumericSimpleTableHeaderCell,
StyledSimpleTableHeader,
Expand All @@ -24,9 +25,13 @@ const ICON_HEADERS = {

interface MetricsSamplesTableHeaderProps {
columns: SampleTableColumnKey[];
embedded?: boolean;
}

export function MetricsSamplesTableHeader({columns}: MetricsSamplesTableHeaderProps) {
export function MetricsSamplesTableHeader({
columns,
embedded,
}: MetricsSamplesTableHeaderProps) {
const sorts = useQueryParamsSortBys();

return (
Expand All @@ -41,6 +46,7 @@ export function MetricsSamplesTableHeader({columns}: MetricsSamplesTableHeaderPr
field={field}
index={i}
sort={sorts.find(s => s.field === field)?.kind}
embedded={embedded}
>
{columnType === 'stat'
? ICON_HEADERS[field as keyof typeof ICON_HEADERS]
Expand All @@ -59,22 +65,25 @@ function FieldHeaderCellWrapper({
children,
index,
sort,
embedded = false,
}: {
children: ReactNode;
field: SampleTableColumnKey;
index: number;
embedded?: boolean;
sort?: 'asc' | 'desc';
}) {
const columnType = getMetricTableColumnType(field);
const label = getFieldLabel(field);
const hasPadding = field !== VirtualTableSampleColumnKey.EXPAND_ROW;
const hasPadding = !NoPaddingColumns.includes(field as VirtualTableSampleColumnKey);

if (columnType === 'stat') {
return (
<NumericSimpleTableHeaderCell
key={`stat-${index}`}
divider={false}
data-column-name={field}
embedded={embedded}
>
<Tooltip title={label} skipWrapper>
{children}
Expand All @@ -92,6 +101,7 @@ function FieldHeaderCellWrapper({
justifyContent: 'flex-end',
paddingRight: 'calc(12px + 15px)', // 12px is the padding of the cell, 15px is the width of the scrollbar.
}}
embedded={embedded}
>
<Tooltip showOnlyOnOverflow title={label}>
{children}
Expand All @@ -101,7 +111,12 @@ function FieldHeaderCellWrapper({
}

return (
<StyledSimpleTableHeaderCell key={index} sort={sort} noPadding={!hasPadding}>
<StyledSimpleTableHeaderCell
key={index}
sort={sort}
noPadding={!hasPadding}
embedded={embedded}
>
<Tooltip showOnlyOnOverflow title={label}>
{children}
</Tooltip>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import {useRef, useState, type ReactNode} from 'react';
import {useTheme} from '@emotion/react';
import styled from '@emotion/styled';

import {Flex} from '@sentry/scraps/layout/flex';

import {Button} from 'sentry/components/core/button';
import {Link} from 'sentry/components/core/link';
import {Tooltip} from 'sentry/components/core/tooltip';
import Count from 'sentry/components/count';
import ProjectBadge from 'sentry/components/idBadge/projectBadge';
import {IconChevron} from 'sentry/icons';
import {t} from 'sentry/locale';
import type {TableDataRow} from 'sentry/utils/discover/discoverQuery';
Expand All @@ -16,17 +18,23 @@ import {FieldValueType} from 'sentry/utils/fields';
import {useLocation} from 'sentry/utils/useLocation';
import useOrganization from 'sentry/utils/useOrganization';
import usePageFilters from 'sentry/utils/usePageFilters';
import useProjects from 'sentry/utils/useProjects';
import type {TableColumn} from 'sentry/views/discover/table/types';
import {TimestampRenderer} from 'sentry/views/explore/logs/fieldRenderers';
import {getLogColors} from 'sentry/views/explore/logs/styles';
import {SeverityLevel} from 'sentry/views/explore/logs/utils';
import {
NoPaddingColumns,
type AlwaysPresentTraceMetricFields,
} from 'sentry/views/explore/metrics/constants';
import {useTraceTelemetry} from 'sentry/views/explore/metrics/hooks/useTraceTelemetry';
import {MetricDetails} from 'sentry/views/explore/metrics/metricInfoTabs/metricDetails';
import {
ExpandedRowContainer,
NumericSimpleTableRowCell,
StickyTableRow,
StyledSimpleTableRowCell,
TableRowContainer,
WrappingText,
} from 'sentry/views/explore/metrics/metricInfoTabs/metricInfoTabStyles';
import {stripMetricParamsFromLocation} from 'sentry/views/explore/metrics/metricQuery';
Expand Down Expand Up @@ -69,7 +77,7 @@ function FieldCellWrapper({
embedded?: boolean;
}) {
const columnType = getMetricTableColumnType(field);
const hasPadding = field !== VirtualTableSampleColumnKey.EXPAND_ROW;
const hasPadding = !NoPaddingColumns.includes(field as VirtualTableSampleColumnKey);
if (columnType === 'stat') {
return (
<NumericSimpleTableRowCell
Expand Down Expand Up @@ -115,6 +123,11 @@ export function SampleTableRow({
const theme = useTheme();
const [isExpanded, setIsExpanded] = useState(false);
const measureRef = useRef<HTMLTableRowElement>(null);
const projects = useProjects();
const projectId: (typeof AlwaysPresentTraceMetricFields)[1] =
row[TraceMetricKnownFieldKey.PROJECT_ID];
const project = projects.projects.find(p => p.id === '' + projectId);
const projectSlug = project?.slug ?? '';

const traceId = row[TraceMetricKnownFieldKey.TRACE];
const telemetry = telemetryData?.get?.(traceId);
Expand All @@ -137,9 +150,9 @@ export function SampleTableRow({
const spanId = row[TraceMetricKnownFieldKey.SPAN_ID];
const oldSpanId = row[TraceMetricKnownFieldKey.OLD_SPAN_ID] as string;
const spanIdToUse = oldSpanId || spanId;
const hasSpans = (telemetry?.spansCount ?? 0) > 0;
const strippedLocation = stripMetricParamsFromLocation(location);

const hasSpans = (telemetry?.spansCount ?? 0) > 0;
const shouldGoToSpans = spanIdToUse && hasSpans;

const target = getTraceDetailsUrl({
Expand All @@ -150,12 +163,12 @@ export function SampleTableRow({
end: selection.datetime.end,
statsPeriod: selection.datetime.period,
},
location: strippedLocation,
timestamp,
source: TraceViewSources.TRACES, // TODO: Should be TraceViewSources.TRACE_METRICS later after the trace view changes
location: strippedLocation,
source: TraceViewSources.TRACE_METRICS,
spanId: shouldGoToSpans ? spanIdToUse : undefined,
// tab: shouldGoToSpans ? TraceLayoutTabKeys.WATERFALL : TraceLayoutTabKeys.METRICS, // TODO: Add metrics tab to trace view
tab: TraceLayoutTabKeys.WATERFALL,
// tab: shouldGoToSpans ? TraceLayoutTabKeys.WATERFALL : TraceLayoutTabKeys.METRICS, // TODO: Can use this if want to go to the waterfall view if we add metrics to span details.
tab: TraceLayoutTabKeys.METRICS,
});

return (
Expand Down Expand Up @@ -263,6 +276,14 @@ export function SampleTableRow({
);
};

const renderProjectCell = () => {
return (
<Flex align="center" justify="center" style={{minWidth: '18px'}}>
<ProjectBadge avatarSize={14} project={project ?? {slug: projectSlug}} hideName />
</Flex>
);
};

const renderMap: Record<SampleTableColumnKey, () => ReactNode> = {
[VirtualTableSampleColumnKey.EXPAND_ROW]: renderExpandRowCell,
[TraceMetricKnownFieldKey.TRACE]: renderTraceCell,
Expand All @@ -271,6 +292,7 @@ export function SampleTableRow({
[VirtualTableSampleColumnKey.LOGS]: renderLogsCell,
[VirtualTableSampleColumnKey.SPANS]: renderSpansCell,
[VirtualTableSampleColumnKey.ERRORS]: renderErrorsCell,
[VirtualTableSampleColumnKey.PROJECT_BADGE]: renderProjectCell,
[TraceMetricKnownFieldKey.METRIC_TYPE]: renderMetricTypeCell,
};

Expand Down Expand Up @@ -315,14 +337,3 @@ export function SampleTableRow({
</TableRowContainer>
);
}

const TableRowContainer = styled('div')`
display: grid;
grid-template-columns: subgrid;
grid-auto-rows: min-content;
grid-column: 1 / -1;

:not(:last-child) {
border-bottom: 1px solid ${p => p.theme.border};
}
`;
2 changes: 1 addition & 1 deletion static/app/views/explore/metrics/metricsFlags.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import type {Organization} from 'sentry/types/organization';

const canUseMetricsUI = (organization: Organization) => {
export const canUseMetricsUI = (organization: Organization) => {
return organization.features.includes('tracemetrics-enabled');
};

Expand Down
35 changes: 33 additions & 2 deletions static/app/views/explore/metrics/metricsFrozenContext.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import type {ReactNode} from 'react';
import {useMemo} from 'react';

import {ALL_ACCESS_PROJECTS} from 'sentry/constants/pageFilters';
import type {DateString} from 'sentry/types/core';
import {createDefinedContext} from 'sentry/utils/performance/contexts/utils';
import {MutableSearch} from 'sentry/utils/tokenizeSearch';
import {TraceMetricKnownFieldKey} from 'sentry/views/explore/metrics/types';

interface TracePeriod {
export interface TracePeriod {
end?: DateString;
period?: string | null;
start?: DateString;
Expand All @@ -16,12 +21,38 @@ interface MetricsFrozenContextValue {
tracePeriod?: TracePeriod;
}

const [_MetricsFrozenContextProvider, _useMetricsFrozenContext] =
const [_MetricsFrozenContextProvider, _useMetricsFrozenContext, MetricsFrozenContext] =
createDefinedContext<MetricsFrozenContextValue>({
name: 'MetricsFrozenContext',
strict: false,
});

export interface MetricsFrozenForTracesProviderProps {
traceIds: string[];
children?: ReactNode;
tracePeriod?: TracePeriod;
}

export function MetricsFrozenContextProvider(props: MetricsFrozenForTracesProviderProps) {
const value: MetricsFrozenContextValue = useMemo(() => {
if (props.traceIds.length) {
const search = new MutableSearch('');
const traceIds = `[${props.traceIds.join(',')}]`;
search.addFilterValue(TraceMetricKnownFieldKey.TRACE, traceIds);
return {
frozen: true,
search,
traceIds: props.traceIds,
projectIds: [ALL_ACCESS_PROJECTS],
tracePeriod: props.tracePeriod,
};
}

return {frozen: false};
}, [props]);

return <MetricsFrozenContext value={value}>{props.children}</MetricsFrozenContext>;
}
function useMetricsFrozenContext() {
return _useMetricsFrozenContext() ?? {};
}
Expand Down
Loading
Loading