Skip to content

Commit e3c6f06

Browse files
committed
feat(flags): add CTA to flag drawer
1 parent e73a5c4 commit e3c6f06

File tree

5 files changed

+104
-7
lines changed

5 files changed

+104
-7
lines changed

static/app/components/events/featureFlags/eventFeatureFlagList.tsx

+3-6
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,12 @@ import FeatureFlagSort from 'sentry/components/events/featureFlags/featureFlagSo
1414
import {
1515
FlagControlOptions,
1616
OrderBy,
17+
shouldShowFeatureFlagCTA,
1718
SortBy,
1819
sortedFlags,
1920
} from 'sentry/components/events/featureFlags/utils';
2021
import useDrawer from 'sentry/components/globalDrawer';
2122
import KeyValueData from 'sentry/components/keyValueData';
22-
import {featureFlagOnboardingPlatforms} from 'sentry/data/platformCategories';
2323
import {IconMegaphone, IconSearch} from 'sentry/icons';
2424
import {t, tn} from 'sentry/locale';
2525
import type {Event, FeatureFlag} from 'sentry/types/event';
@@ -219,11 +219,8 @@ export function EventFeatureFlagList({
219219
}
220220

221221
// contexts.flags is not set and project has not ingested flags
222-
if (!hasFlagContext && !project.hasFlags) {
223-
const showCTA =
224-
featureFlagOnboardingPlatforms.includes(project.platform ?? 'other') &&
225-
organization.features.includes('feature-flag-cta');
226-
return showCTA ? <FeatureFlagInlineCTA projectId={event.projectID} /> : null;
222+
if (!hasFlagContext && shouldShowFeatureFlagCTA(organization, project)) {
223+
return <FeatureFlagInlineCTA projectId={event.projectID} />;
227224
}
228225

229226
const actions = (

static/app/components/events/featureFlags/utils.tsx

+11
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import type {KeyValueDataContentProps} from 'sentry/components/keyValueData';
2+
import {featureFlagOnboardingPlatforms} from 'sentry/data/platformCategories';
23
import {t} from 'sentry/locale';
4+
import type {Organization} from 'sentry/types/organization';
5+
import type {Project} from 'sentry/types/project';
36

47
export enum OrderBy {
58
NEWEST = 'newest',
@@ -139,3 +142,11 @@ export const PROVIDER_TO_SETUP_WEBHOOK_URL: Record<WebhookProviderEnum, string>
139142
[WebhookProviderEnum.UNLEASH]:
140143
'https://docs.sentry.io/organization/integrations/feature-flag/unleash/#set-up-change-tracking',
141144
};
145+
146+
export function shouldShowFeatureFlagCTA(organization: Organization, project: Project) {
147+
return (
148+
!project.hasFlags &&
149+
featureFlagOnboardingPlatforms.includes(project.platform ?? 'other') &&
150+
organization.features.includes('feature-flag-cta')
151+
);
152+
}

static/app/components/globalDrawer/components.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ const DrawerContentContext = createContext<DrawerContentContextType>({
1919
ariaLabel: 'slide out drawer',
2020
});
2121

22-
function useDrawerContentContext() {
22+
export function useDrawerContentContext() {
2323
return useContext(DrawerContentContext);
2424
}
2525

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import styled from '@emotion/styled';
2+
3+
import {Button, LinkButton} from 'sentry/components/core/button';
4+
import {useFeatureFlagOnboarding} from 'sentry/components/events/featureFlags/useFeatureFlagOnboarding';
5+
import {useDrawerContentContext} from 'sentry/components/globalDrawer/components';
6+
import {t} from 'sentry/locale';
7+
import {space} from 'sentry/styles/space';
8+
import {trackAnalytics} from 'sentry/utils/analytics';
9+
import useOrganization from 'sentry/utils/useOrganization';
10+
11+
export default function FlagDrawerCTA() {
12+
const organization = useOrganization();
13+
const {activateSidebar} = useFeatureFlagOnboarding();
14+
const {onClose: closeDrawer} = useDrawerContentContext();
15+
16+
function handleSetupButtonClick(e: any) {
17+
trackAnalytics('flags.setup_modal_opened', {organization});
18+
trackAnalytics('flags.cta_setup_button_clicked', {organization});
19+
closeDrawer?.();
20+
setTimeout(() => {
21+
// Wait for global drawer state to update
22+
activateSidebar(e);
23+
}, 100);
24+
}
25+
26+
return (
27+
<BannerWrapper>
28+
<BannerTitle>{t('Set Up Feature Flags')}</BannerTitle>
29+
<BannerDescription>
30+
{t(
31+
'Want to know which feature flags were associated with this error? Set up your feature flag integration.'
32+
)}
33+
</BannerDescription>
34+
<ActionButton>
35+
<Button onClick={handleSetupButtonClick} priority="primary">
36+
{t('Set Up Now')}
37+
</Button>
38+
<LinkButton
39+
priority="default"
40+
href="https://docs.sentry.io/product/explore/feature-flags/"
41+
external
42+
>
43+
{t('Read More')}
44+
</LinkButton>
45+
</ActionButton>
46+
</BannerWrapper>
47+
);
48+
}
49+
50+
const BannerTitle = styled('div')`
51+
font-size: ${p => p.theme.fontSizeExtraLarge};
52+
margin-bottom: ${space(1)};
53+
font-weight: ${p => p.theme.fontWeightBold};
54+
`;
55+
56+
const BannerDescription = styled('div')`
57+
margin-bottom: ${space(1.5)};
58+
max-width: 340px;
59+
`;
60+
61+
const ActionButton = styled('div')`
62+
display: flex;
63+
gap: ${space(1)};
64+
`;
65+
66+
const BannerWrapper = styled('div')`
67+
position: relative;
68+
border: 1px solid ${p => p.theme.border};
69+
border-radius: ${p => p.theme.borderRadius};
70+
padding: ${space(2)};
71+
margin: ${space(1)} 0;
72+
background: linear-gradient(
73+
90deg,
74+
${p => p.theme.backgroundSecondary}00 0%,
75+
${p => p.theme.backgroundSecondary}FF 70%,
76+
${p => p.theme.backgroundSecondary}FF 100%
77+
);
78+
`;

static/app/views/issueDetails/groupFeatureFlags/groupFeatureFlagsDrawerContent.tsx

+11
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
import {useMemo} from 'react';
22

3+
import {shouldShowFeatureFlagCTA} from 'sentry/components/events/featureFlags/utils';
34
import LoadingError from 'sentry/components/loadingError';
45
import LoadingIndicator from 'sentry/components/loadingIndicator';
56
import {t} from 'sentry/locale';
67
import type {Group} from 'sentry/types/group';
8+
import useOrganization from 'sentry/utils/useOrganization';
9+
import useProjectFromSlug from 'sentry/utils/useProjectFromSlug';
10+
import FlagDrawerCTA from 'sentry/views/issueDetails/groupFeatureFlags/flagDrawerCTA';
711
import useGroupFeatureFlags from 'sentry/views/issueDetails/groupFeatureFlags/useGroupFeatureFlags';
812
import {
913
Container,
@@ -61,6 +65,13 @@ export default function GroupFeatureFlagsDrawerContent({
6165
return searchedTags;
6266
}, [data, search, tagValues]);
6367

68+
const organization = useOrganization();
69+
const project = useProjectFromSlug({organization, projectSlug: group.project?.slug});
70+
71+
if (data.length === 0 && project && shouldShowFeatureFlagCTA(organization, project)) {
72+
return <FlagDrawerCTA />;
73+
}
74+
6475
return isPending ? (
6576
<LoadingIndicator />
6677
) : isError ? (

0 commit comments

Comments
 (0)