Skip to content

Commit 21ba6b9

Browse files
authored
feat(insights): add ttfd/ttid filters on screen load module (#101268)
Some customers requested an ability to see the which spans affect ttid/ttfd, or don't affect anything at all. We can do this with a simple filter <img width="1210" height="423" alt="image" src="https://github.com/user-attachments/assets/9463dc64-5e0f-4057-92b3-b96bf1c9fed0" />
1 parent d3f9849 commit 21ba6b9

File tree

4 files changed

+95
-7
lines changed

4 files changed

+95
-7
lines changed
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import styled from '@emotion/styled';
2+
3+
import {CompactSelect, type SelectOption} from 'sentry/components/core/compactSelect';
4+
import {t} from 'sentry/locale';
5+
import {space} from 'sentry/styles/space';
6+
import {useTTFDConfigured} from 'sentry/views/insights/common/queries/useHasTtfdConfigured';
7+
import {useAffectsSelection} from 'sentry/views/insights/mobile/screenload/data/useAffectsSelection';
8+
9+
export function AffectSelector({transaction}: {transaction?: string}) {
10+
const {value, setValue} = useAffectsSelection();
11+
const {hasTTFD} = useTTFDConfigured([`transaction:"${transaction}"`]);
12+
13+
const options: Array<SelectOption<'TTID' | 'TTFD' | 'NONE' | 'ALL'>> = [
14+
{value: 'ALL', label: t('All')},
15+
{value: 'TTID', label: t('TTID')},
16+
];
17+
18+
if (hasTTFD) {
19+
options.push({value: 'TTFD', label: t('TTFD')});
20+
}
21+
22+
options.push({value: 'NONE', label: t('None')});
23+
24+
return (
25+
<StyledCompactSelect
26+
disallowEmptySelection
27+
triggerProps={{prefix: t('Affects'), size: 'xs'}}
28+
value={value}
29+
options={options}
30+
onChange={newValue => {
31+
setValue(newValue.value);
32+
}}
33+
/>
34+
);
35+
}
36+
37+
const StyledCompactSelect = styled(CompactSelect)`
38+
margin-bottom: ${space(1)};
39+
`;

static/app/views/insights/mobile/screenload/components/tables/screenLoadSpansTable.tsx

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {Fragment, useMemo} from 'react';
2-
import {useTheme} from '@emotion/react';
2+
import {useTheme, type Theme} from '@emotion/react';
33
import styled from '@emotion/styled';
44
import * as qs from 'query-string';
55

@@ -33,11 +33,13 @@ import {appendReleaseFilters} from 'sentry/views/insights/common/utils/releaseCo
3333
import {useModuleURL} from 'sentry/views/insights/common/utils/useModuleURL';
3434
import {QueryParameterNames} from 'sentry/views/insights/common/views/queryParameters';
3535
import useCrossPlatformProject from 'sentry/views/insights/mobile/common/queries/useCrossPlatformProject';
36+
import {AffectSelector} from 'sentry/views/insights/mobile/screenload/components/affectSelector';
3637
import {
3738
SpanOpSelector,
3839
TTID_CONTRIBUTING_SPAN_OPS,
3940
} from 'sentry/views/insights/mobile/screenload/components/spanOpSelector';
4041
import {MobileCursors} from 'sentry/views/insights/mobile/screenload/constants';
42+
import {useAffectsSelection} from 'sentry/views/insights/mobile/screenload/data/useAffectsSelection';
4143
import {MODULE_DOC_LINK} from 'sentry/views/insights/mobile/screenload/settings';
4244
import {ModuleName, SpanFields} from 'sentry/views/insights/types';
4345

@@ -64,6 +66,7 @@ export function ScreenLoadSpansTable({
6466
const location = useLocation();
6567
const cursor = decodeScalar(location.query?.[MobileCursors.SPANS_TABLE]);
6668
const {isProjectCrossPlatform, selectedPlatform} = useCrossPlatformProject();
69+
const {value: affects} = useAffectsSelection();
6770

6871
const spanOp = decodeScalar(location.query[SpanFields.SPAN_OP]) ?? '';
6972
const {hasTTFD, isPending: hasTTFDLoading} = useTTFDConfigured([
@@ -84,6 +87,15 @@ export function ScreenLoadSpansTable({
8487
searchQuery.addFilterValue('os.name', selectedPlatform);
8588
}
8689

90+
if (affects === 'NONE') {
91+
searchQuery.addFilterValue(`!${SpanFields.TTFD}`, 'ttfd');
92+
searchQuery.addFilterValue(`!${SpanFields.TTID}`, 'ttid');
93+
} else if (affects === 'TTFD') {
94+
searchQuery.addFilterValue(SpanFields.TTFD, 'ttfd');
95+
} else if (affects === 'TTID') {
96+
searchQuery.addFilterValue(SpanFields.TTID, 'ttid');
97+
}
98+
8799
return appendReleaseFilters(searchQuery, primaryRelease, secondaryRelease);
88100
}, [
89101
isProjectCrossPlatform,
@@ -92,6 +104,7 @@ export function ScreenLoadSpansTable({
92104
selectedPlatform,
93105
spanOp,
94106
transaction,
107+
affects,
95108
]);
96109

97110
const sort = decodeSorts(location.query[QueryParameterNames.SPANS_SORT])[0] ?? {
@@ -361,11 +374,14 @@ export function ScreenLoadSpansTable({
361374

362375
return (
363376
<Fragment>
364-
<SpanOpSelector
365-
primaryRelease={primaryRelease}
366-
transaction={transaction}
367-
secondaryRelease={secondaryRelease}
368-
/>
377+
<ButtonContainer theme={theme}>
378+
<SpanOpSelector
379+
primaryRelease={primaryRelease}
380+
transaction={transaction}
381+
secondaryRelease={secondaryRelease}
382+
/>
383+
<AffectSelector transaction={transaction} />
384+
</ButtonContainer>
369385
<GridEditable
370386
isLoading={isPending || hasTTFDLoading}
371387
data={data}
@@ -386,3 +402,8 @@ const Container = styled('div')`
386402
${p => p.theme.overflowEllipsis};
387403
text-align: right;
388404
`;
405+
406+
const ButtonContainer = styled('div')<{theme: Theme}>`
407+
display: flex;
408+
gap: ${p => p.theme.space.md};
409+
`;
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import {useQueryState} from 'nuqs';
2+
3+
import type {SelectKey} from 'sentry/components/core/compactSelect';
4+
5+
const DEFAULT_VALUE = 'ALL';
6+
7+
const AffectOptions = ['ALL', 'TTID', 'TTFD', 'NONE'];
8+
9+
export function useAffectsSelection() {
10+
const [queryState, setQueryState] = useQueryState('affects');
11+
const isValid = AffectOptions.includes(queryState ?? '');
12+
const value = (isValid ? queryState : DEFAULT_VALUE) as
13+
| 'ALL'
14+
| 'TTID'
15+
| 'TTFD'
16+
| 'NONE';
17+
18+
const setQueryStateWrapper = (newValue: SelectKey) => {
19+
if (typeof newValue === 'string') {
20+
setQueryState(newValue);
21+
}
22+
};
23+
return {value, setValue: setQueryStateWrapper};
24+
}

static/app/views/insights/types.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,8 @@ export enum SpanFields {
127127
APP_START_WARM = 'measurements.app_start_warm',
128128
MOBILE_FRAMES_DELAY = 'mobile.frames_delay',
129129
APP_START_TYPE = 'app_start_type',
130+
TTID = 'sentry.ttid',
131+
TTFD = 'sentry.ttfd',
130132

131133
// Messaging fields
132134
MESSAGING_MESSAGE_ID = 'messaging.message.id',
@@ -226,7 +228,9 @@ export type SpanNumberFields =
226228
| SpanFields.PRECISE_START_TS
227229
| SpanFields.PRECISE_FINISH_TS
228230
| SpanFields.THREAD_ID
229-
| SpanFields.PROJECT_ID;
231+
| SpanFields.PROJECT_ID
232+
| SpanFields.TTID
233+
| SpanFields.TTFD;
230234

231235
// TODO: Enforce that these fields all come from SpanFields
232236
export type SpanStringFields =

0 commit comments

Comments
 (0)