|
@@ -1,12 +1,20 @@
|
|
|
+import {Fragment} from 'react';
|
|
|
+import styled from '@emotion/styled';
|
|
|
+
|
|
|
import DateTime from 'sentry/components/dateTime';
|
|
|
import Duration from 'sentry/components/duration';
|
|
|
import GridEditable, {GridColumnHeader} from 'sentry/components/gridEditable';
|
|
|
import Link from 'sentry/components/links/link';
|
|
|
+import QuestionTooltip from 'sentry/components/questionTooltip';
|
|
|
+import {t} from 'sentry/locale';
|
|
|
import {NewQuery} from 'sentry/types';
|
|
|
import EventView from 'sentry/utils/discover/eventView';
|
|
|
+import {getFieldRenderer} from 'sentry/utils/discover/fieldRenderers';
|
|
|
+import {SPAN_OP_RELATIVE_BREAKDOWN_FIELD} from 'sentry/utils/discover/fields';
|
|
|
import {DiscoverDatasets} from 'sentry/utils/discover/types';
|
|
|
import {MutableSearch} from 'sentry/utils/tokenizeSearch';
|
|
|
import {useLocation} from 'sentry/utils/useLocation';
|
|
|
+import useOrganization from 'sentry/utils/useOrganization';
|
|
|
import {DurationComparisonCell} from 'sentry/views/starfish/components/samplesTable/common';
|
|
|
import useSlowMedianFastSamplesQuery from 'sentry/views/starfish/components/samplesTable/useSlowMedianFastSamplesQuery';
|
|
|
import {
|
|
@@ -15,7 +23,13 @@ import {
|
|
|
TextAlignRight,
|
|
|
} from 'sentry/views/starfish/components/textAlign';
|
|
|
|
|
|
-type Keys = 'id' | 'profile_id' | 'timestamp' | 'transaction.duration' | 'p95_comparison';
|
|
|
+type Keys =
|
|
|
+ | 'id'
|
|
|
+ | 'profile_id'
|
|
|
+ | 'timestamp'
|
|
|
+ | 'transaction.duration'
|
|
|
+ | 'p95_comparison'
|
|
|
+ | 'span_ops_breakdown.relative';
|
|
|
type TableColumnHeader = GridColumnHeader<Keys>;
|
|
|
|
|
|
const COLUMN_ORDER: TableColumnHeader[] = [
|
|
@@ -29,6 +43,11 @@ const COLUMN_ORDER: TableColumnHeader[] = [
|
|
|
name: 'Profile ID',
|
|
|
width: 140,
|
|
|
},
|
|
|
+ {
|
|
|
+ key: SPAN_OP_RELATIVE_BREAKDOWN_FIELD,
|
|
|
+ name: 'Operation Duration',
|
|
|
+ width: 200,
|
|
|
+ },
|
|
|
{
|
|
|
key: 'timestamp',
|
|
|
name: 'Timestamp',
|
|
@@ -53,12 +72,18 @@ type Props = {
|
|
|
type DataRow = {
|
|
|
id: string;
|
|
|
profile_id: string;
|
|
|
+ 'spans.browser': number;
|
|
|
+ 'spans.db': number;
|
|
|
+ 'spans.http': number;
|
|
|
+ 'spans.resource': number;
|
|
|
+ 'spans.ui': number;
|
|
|
timestamp: string;
|
|
|
'transaction.duration': number;
|
|
|
};
|
|
|
|
|
|
export function TransactionSamplesTable({queryConditions}: Props) {
|
|
|
const location = useLocation();
|
|
|
+ const organization = useOrganization();
|
|
|
const query = new MutableSearch(queryConditions);
|
|
|
|
|
|
const savedQuery: NewQuery = {
|
|
@@ -83,6 +108,21 @@ export function TransactionSamplesTable({queryConditions}: Props) {
|
|
|
);
|
|
|
}
|
|
|
|
|
|
+ if (column.key === SPAN_OP_RELATIVE_BREAKDOWN_FIELD) {
|
|
|
+ return (
|
|
|
+ <Fragment>
|
|
|
+ {column.name}
|
|
|
+ <StyledIconQuestion
|
|
|
+ size="xs"
|
|
|
+ position="top"
|
|
|
+ title={t(
|
|
|
+ `Span durations are summed over the course of an entire transaction. Any overlapping spans are only counted once.`
|
|
|
+ )}
|
|
|
+ />
|
|
|
+ </Fragment>
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
return <OverflowEllipsisTextContainer>{column.name}</OverflowEllipsisTextContainer>;
|
|
|
}
|
|
|
|
|
@@ -130,6 +170,14 @@ export function TransactionSamplesTable({queryConditions}: Props) {
|
|
|
);
|
|
|
}
|
|
|
|
|
|
+ if (column.key === SPAN_OP_RELATIVE_BREAKDOWN_FIELD) {
|
|
|
+ return getFieldRenderer(column.key, {})(row, {
|
|
|
+ location,
|
|
|
+ organization,
|
|
|
+ eventView,
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
return <TextAlignLeft>{row[column.key]}</TextAlignLeft>;
|
|
|
}
|
|
|
|
|
@@ -147,3 +195,8 @@ export function TransactionSamplesTable({queryConditions}: Props) {
|
|
|
/>
|
|
|
);
|
|
|
}
|
|
|
+
|
|
|
+const StyledIconQuestion = styled(QuestionTooltip)`
|
|
|
+ position: relative;
|
|
|
+ left: 4px;
|
|
|
+`;
|