Skip to content

Commit 8b6bb09

Browse files
ryan953billyvg
andauthored
replay(feat): Add a new badge on the Replay Details>Network tab to announce the feature (#47997)
Guarded by the feature flag: `organizations:session-replay-network-details` ![SCR-20230426-jatv](https://user-images.githubusercontent.com/187460/234646478-5eb2c3be-776c-4258-a861-d0cfd57daea3.png) Fixes #47834 --------- Co-authored-by: Billy Vong <[email protected]>
1 parent f086416 commit 8b6bb09

File tree

2 files changed

+73
-11
lines changed

2 files changed

+73
-11
lines changed

static/app/views/replays/detail/layout/focusTabs.tsx

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,38 @@
1-
import {ReactNode} from 'react';
1+
import {Fragment, ReactNode} from 'react';
22
import queryString from 'query-string';
33

4+
import FeatureBadge from 'sentry/components/featureBadge';
45
import ListLink from 'sentry/components/links/listLink';
56
import ScrollableTabs from 'sentry/components/replays/scrollableTabs';
67
import {t} from 'sentry/locale';
8+
import {Organization} from 'sentry/types';
79
import {trackAnalytics} from 'sentry/utils/analytics';
810
import useActiveReplayTab, {TabKey} from 'sentry/utils/replays/hooks/useActiveReplayTab';
911
import {useLocation} from 'sentry/utils/useLocation';
1012
import useOrganization from 'sentry/utils/useOrganization';
1113

12-
const ReplayTabs: Record<TabKey, ReactNode> = {
13-
[TabKey.console]: t('Console'),
14-
[TabKey.network]: t('Network'),
15-
[TabKey.dom]: t('DOM Events'),
16-
[TabKey.issues]: t('Issues'),
17-
[TabKey.memory]: t('Memory'),
18-
[TabKey.trace]: t('Trace'),
19-
};
14+
function getReplayTabs(organization: Organization): Record<TabKey, ReactNode> {
15+
const hasReplayNetworkDetails = organization.features.includes(
16+
'session-replay-network-details'
17+
);
18+
19+
const networkLabel = hasReplayNetworkDetails ? (
20+
<Fragment>
21+
{t('Network')} <FeatureBadge type="new" />
22+
</Fragment>
23+
) : (
24+
t('Network')
25+
);
26+
27+
return {
28+
[TabKey.console]: t('Console'),
29+
[TabKey.network]: networkLabel,
30+
[TabKey.dom]: t('DOM Events'),
31+
[TabKey.issues]: t('Issues'),
32+
[TabKey.memory]: t('Memory'),
33+
[TabKey.trace]: t('Trace'),
34+
};
35+
}
2036

2137
type Props = {
2238
className?: string;
@@ -30,7 +46,7 @@ function FocusTabs({className}: Props) {
3046

3147
return (
3248
<ScrollableTabs className={className} underlined>
33-
{Object.entries(ReplayTabs).map(([tab, label]) => (
49+
{Object.entries(getReplayTabs(organization)).map(([tab, label]) => (
3450
<ListLink
3551
key={tab}
3652
isActive={() => tab === activeTab}

static/app/views/replays/detail/network/index.tsx

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,16 @@ import {AutoSizer, CellMeasurer, GridCellProps, MultiGrid} from 'react-virtualiz
33
import styled from '@emotion/styled';
44

55
import Feature from 'sentry/components/acl/feature';
6+
import {Alert} from 'sentry/components/alert';
7+
import {Button} from 'sentry/components/button';
8+
import ExternalLink from 'sentry/components/links/externalLink';
69
import Placeholder from 'sentry/components/placeholder';
710
import {useReplayContext} from 'sentry/components/replays/replayContext';
8-
import {t} from 'sentry/locale';
11+
import {IconClose, IconInfo} from 'sentry/icons';
12+
import {t, tct} from 'sentry/locale';
13+
import {space} from 'sentry/styles/space';
914
import useCrumbHandlers from 'sentry/utils/replays/hooks/useCrumbHandlers';
15+
import useDismissAlert from 'sentry/utils/useDismissAlert';
1016
import useOrganization from 'sentry/utils/useOrganization';
1117
import FluidHeight from 'sentry/views/replays/detail/layout/fluidHeight';
1218
import NetworkDetails from 'sentry/views/replays/detail/network/networkDetails';
@@ -39,6 +45,8 @@ function NetworkList({networkSpans, startTimestampMs}: Props) {
3945
const organization = useOrganization();
4046
const {currentTime, currentHoverTime} = useReplayContext();
4147

48+
const {dismiss, isDismissed} = useDismissAlert({key: 'replay-network-bodies'});
49+
4250
const initialRequestDetailsHeight = useMemo(
4351
() => Math.max(150, window.innerHeight * 0.25),
4452
[]
@@ -113,6 +121,36 @@ function NetworkList({networkSpans, startTimestampMs}: Props) {
113121
return (
114122
<FluidHeight>
115123
<NetworkFilters networkSpans={networkSpans} {...filterProps} />
124+
<Feature
125+
features={['session-replay-network-details']}
126+
organization={organization}
127+
renderDisabled={false}
128+
>
129+
{isDismissed ? null : (
130+
<StyledAlert
131+
icon={<IconInfo />}
132+
opaque={false}
133+
showIcon
134+
type="info"
135+
trailingItems={
136+
<StyledButton priority="link" size="sm" onClick={() => {}}>
137+
<IconClose color="gray500" size="sm" />
138+
</StyledButton>
139+
}
140+
>
141+
{tct('Start collecting the body of requests and responses. [link]', {
142+
link: (
143+
<ExternalLink
144+
href="https://github.com/getsentry/sentry-javascript/issues/7103"
145+
onClick={dismiss}
146+
>
147+
{t('Learn More')}
148+
</ExternalLink>
149+
),
150+
})}
151+
</StyledAlert>
152+
)}
153+
</Feature>
116154
<NetworkTable>
117155
<FluidHeight>
118156
{networkSpans ? (
@@ -214,4 +252,12 @@ const NetworkTable = styled(OverflowHidden)`
214252
}
215253
`;
216254

255+
const StyledAlert = styled(Alert)`
256+
margin-bottom: ${space(1)};
257+
`;
258+
259+
const StyledButton = styled(Button)`
260+
color: inherit;
261+
`;
262+
217263
export default NetworkList;

0 commit comments

Comments
 (0)