Skip to content

Commit 3277abc

Browse files
authored
chore(feedback): Prefer <FeedbackButton> over useFeedbackForm() (#103916)
This updates most of the callsites to use `<FeedbackButton>` when before it was using `useFeedbackForm()`. The element is easier to use than the hook, takes less code and has reasonable defaults that will save you time and extra code. By having most of the examples in the app use the easier element form, people should be copy+pasting the better form, and the LLMS will hopefully prefer it too. Along the way i noticed a few places that were not translating strings, and/or passing inappropriate stuff to data-aria-label. This is cleaned up. There are more spots in these same files that are missing translations, but i only changed things related to feedback. I tweaked the FeedbackButton itself so it can better behave as an icon-only button. The Thumbs Up/Down pattern is used twice that i found. There's a few other places that still call `useFeedbackForm()` directly, some can be changed over (bug i didn't find them in the app to test them out) while others are like menu items and stuff that don't need to use a Button.
1 parent a162c3d commit 3277abc

File tree

22 files changed

+286
-490
lines changed

22 files changed

+286
-490
lines changed
Lines changed: 12 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,18 @@
1-
import {useRef} from 'react';
2-
3-
import {Button} from 'sentry/components/core/button';
1+
import FeedbackButton from 'sentry/components/feedbackButton/feedbackButton';
42
import {t} from 'sentry/locale';
5-
import {useFeedbackForm} from 'sentry/utils/useFeedbackForm';
6-
7-
function AutofixFeedback() {
8-
const buttonRef = useRef<HTMLButtonElement>(null);
9-
const openForm = useFeedbackForm();
10-
11-
if (!openForm) {
12-
return null;
13-
}
143

4+
export default function AutofixFeedback() {
155
return (
16-
<Button
17-
ref={buttonRef}
6+
<FeedbackButton
187
size="xs"
19-
onClick={() =>
20-
openForm({
21-
formTitle: t('Give feedback to the devs'),
22-
messagePlaceholder: t('How can we make Seer better for you?'),
23-
tags: {
24-
['feedback.source']: 'issue_details_ai_autofix',
25-
['feedback.owner']: 'ml-ai',
26-
},
27-
})
28-
}
29-
>
30-
{t('Give Us Feedback')}
31-
</Button>
8+
feedbackOptions={{
9+
formTitle: t('Give feedback to the devs'),
10+
messagePlaceholder: t('How can we make Seer better for you?'),
11+
tags: {
12+
['feedback.source']: 'issue_details_ai_autofix',
13+
['feedback.owner']: 'ml-ai',
14+
},
15+
}}
16+
/>
3217
);
3318
}
34-
35-
export default AutofixFeedback;

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

Lines changed: 15 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -22,19 +22,19 @@ import {
2222
sortedFlags,
2323
} from 'sentry/components/events/featureFlags/utils';
2424
import {useOrganizationFlagLog} from 'sentry/components/featureFlags/hooks/useOrganizationFlagLog';
25+
import FeedbackButton from 'sentry/components/feedbackButton/feedbackButton';
2526
import useDrawer from 'sentry/components/globalDrawer';
2627
import {useGroupSuspectFlagScores} from 'sentry/components/issues/suspect/useGroupSuspectFlagScores';
2728
import useLegacyEventSuspectFlags from 'sentry/components/issues/suspect/useLegacyEventSuspectFlags';
2829
import useSuspectFlagScoreThreshold from 'sentry/components/issues/suspect/useSuspectFlagScoreThreshold';
2930
import {KeyValueData} from 'sentry/components/keyValueData';
30-
import {IconMegaphone, IconSearch} from 'sentry/icons';
31+
import {IconSearch} from 'sentry/icons';
3132
import {t, tn} from 'sentry/locale';
3233
import type {Event, FeatureFlag} from 'sentry/types/event';
3334
import {IssueCategory, type Group} from 'sentry/types/group';
3435
import type {Project} from 'sentry/types/project';
3536
import {trackAnalytics} from 'sentry/utils/analytics';
3637
import {MutableSearch} from 'sentry/utils/tokenizeSearch';
37-
import {useFeedbackForm} from 'sentry/utils/useFeedbackForm';
3838
import {useLocation} from 'sentry/utils/useLocation';
3939
import useMedia from 'sentry/utils/useMedia';
4040
import useOrganization from 'sentry/utils/useOrganization';
@@ -63,26 +63,19 @@ function BaseEventFeatureFlagList({event, group, project}: EventFeatureFlagSecti
6363
const theme = useTheme();
6464
const isXsScreen = useMedia(`(max-width: ${theme.breakpoints.xs})`);
6565

66-
const openForm = useFeedbackForm();
67-
const feedbackButton =
68-
openForm && !isXsScreen ? (
69-
<Button
70-
aria-label={t('Give feedback on the feature flag section')}
71-
icon={<IconMegaphone />}
72-
size="xs"
73-
onClick={() =>
74-
openForm({
75-
messagePlaceholder: t('How can we make feature flags work better for you?'),
76-
tags: {
77-
['feedback.source']: 'issue_details_feature_flags',
78-
['feedback.owner']: 'replay',
79-
},
80-
})
81-
}
82-
>
83-
{t('Give Feedback')}
84-
</Button>
85-
) : null;
66+
const feedbackButton = isXsScreen ? null : (
67+
<FeedbackButton
68+
aria-label={t('Give feedback on the feature flag section')}
69+
size="xs"
70+
feedbackOptions={{
71+
messagePlaceholder: t('How can we make feature flags work better for you?'),
72+
tags: {
73+
['feedback.source']: 'issue_details_feature_flags',
74+
['feedback.owner']: 'replay',
75+
},
76+
}}
77+
/>
78+
);
8679

8780
// If we're showing the suspect section at all
8881
const enableSuspectFlags = organization.features.includes('feature-flag-suspect-flags');

static/app/components/feedback/summaryCategories/feedbackSummaryCategories.tsx

Lines changed: 18 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,20 @@
11
import styled from '@emotion/styled';
22

33
import {AiPrivacyTooltip} from 'sentry/components/aiPrivacyTooltip';
4-
import {Button} from 'sentry/components/core/button';
54
import {Disclosure} from 'sentry/components/core/disclosure';
65
import {Flex} from 'sentry/components/core/layout';
76
import {useOrganizationSeerSetup} from 'sentry/components/events/autofix/useOrganizationSeerSetup';
87
import FeedbackCategories from 'sentry/components/feedback/summaryCategories/feedbackCategories';
98
import FeedbackSummary from 'sentry/components/feedback/summaryCategories/feedbackSummary';
9+
import FeedbackButton from 'sentry/components/feedbackButton/feedbackButton';
1010
import {IconThumb} from 'sentry/icons';
1111
import {t} from 'sentry/locale';
12-
import {useFeedbackForm} from 'sentry/utils/useFeedbackForm';
1312
import useOrganization from 'sentry/utils/useOrganization';
1413
import {useSyncedLocalStorageState} from 'sentry/utils/useSyncedLocalStorageState';
1514

1615
export default function FeedbackSummaryCategories() {
1716
const organization = useOrganization();
1817

19-
const openForm = useFeedbackForm();
20-
2118
const {areAiFeaturesAllowed} = useOrganizationSeerSetup();
2219

2320
const [isExpanded, setIsExpanded] = useSyncedLocalStorageState(
@@ -35,27 +32,27 @@ export default function FeedbackSummaryCategories() {
3532
}
3633

3734
const feedbackButton = ({type}: {type: 'positive' | 'negative'}) => {
38-
return openForm ? (
39-
<Button
35+
return (
36+
<FeedbackButton
4037
aria-label={t('Give feedback on the AI-powered summary')}
4138
icon={<IconThumb direction={type === 'positive' ? 'up' : 'down'} />}
4239
title={type === 'positive' ? t('I like this') : t(`I don't like this`)}
4340
size="xs"
44-
onClick={() =>
45-
openForm({
46-
messagePlaceholder:
47-
type === 'positive'
48-
? t('What did you like about the AI-powered summary?')
49-
: t('How can we make the summary work better for you?'),
50-
tags: {
51-
['feedback.source']: 'feedback_ai_summary',
52-
['feedback.owner']: 'replay',
53-
['feedback.type']: type,
54-
},
55-
})
56-
}
57-
/>
58-
) : null;
41+
feedbackOptions={{
42+
messagePlaceholder:
43+
type === 'positive'
44+
? t('What did you like about the AI-powered summary?')
45+
: t('How can we make the summary work better for you?'),
46+
tags: {
47+
['feedback.source']: 'feedback_ai_summary',
48+
['feedback.owner']: 'replay',
49+
['feedback.type']: type,
50+
},
51+
}}
52+
>
53+
{undefined}
54+
</FeedbackButton>
55+
);
5956
};
6057

6158
return (

static/app/components/feedbackButton/feedbackButton.tsx

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1-
import {useRef} from 'react';
1+
import {useRef, type ReactNode} from 'react';
22

33
import {Button, type ButtonProps} from 'sentry/components/core/button';
44
import {type UseFeedbackOptions} from 'sentry/components/feedbackButton/useFeedbackSDKIntegration';
55
import {IconMegaphone} from 'sentry/icons/iconMegaphone';
66
import {t} from 'sentry/locale';
77
import {useFeedbackForm} from 'sentry/utils/useFeedbackForm';
88

9-
interface Props extends Omit<ButtonProps, 'icon'> {
9+
interface Props extends Omit<ButtonProps, 'children'> {
10+
children?: ReactNode;
1011
feedbackOptions?: UseFeedbackOptions;
1112
}
1213

@@ -49,11 +50,7 @@ interface Props extends Omit<ButtonProps, 'icon'> {
4950
*
5051
* @returns A Button that opens the feedback widget on click, or null if feedback is not enabled
5152
*/
52-
export default function FeedbackButton({
53-
feedbackOptions,
54-
children,
55-
...buttonProps
56-
}: Props) {
53+
export default function FeedbackButton({feedbackOptions, ...buttonProps}: Props) {
5754
const buttonRef = useRef<HTMLButtonElement>(null);
5855
const openForm = useFeedbackForm();
5956

@@ -62,18 +59,20 @@ export default function FeedbackButton({
6259
return null;
6360
}
6461

62+
const children = 'children' in buttonProps ? buttonProps.children : t('Give Feedback');
63+
6564
return (
6665
<Button
6766
ref={buttonRef}
6867
size="sm"
69-
{...buttonProps}
7068
icon={<IconMegaphone />}
69+
{...buttonProps}
7170
onClick={e => {
7271
openForm?.(feedbackOptions);
7372
buttonProps.onClick?.(e);
7473
}}
7574
>
76-
{children || t('Give Feedback')}
75+
{children}
7776
</Button>
7877
);
7978
}

static/app/components/searchQueryBuilder/tokens/filterKeyListBox/index.tsx

Lines changed: 11 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import type {
1414
SelectOptionOrSectionWithKey,
1515
} from 'sentry/components/core/compactSelect/types';
1616
import InteractionStateLayer from 'sentry/components/core/interactionStateLayer';
17+
import FeedbackButton from 'sentry/components/feedbackButton/feedbackButton';
1718
import {Overlay} from 'sentry/components/overlay';
1819
import {AskSeer} from 'sentry/components/searchQueryBuilder/askSeer/askSeer';
1920
import {ASK_SEER_CONSENT_ITEM_KEY} from 'sentry/components/searchQueryBuilder/askSeer/askSeerConsentOption';
@@ -29,9 +30,7 @@ import {
2930
} from 'sentry/components/searchQueryBuilder/tokens/filterKeyListBox/utils';
3031
import type {Token, TokenResult} from 'sentry/components/searchSyntax/parser';
3132
import {getKeyLabel, getKeyName} from 'sentry/components/searchSyntax/utils';
32-
import {IconMegaphone} from 'sentry/icons';
3333
import {t} from 'sentry/locale';
34-
import {useFeedbackForm} from 'sentry/utils/useFeedbackForm';
3534
import usePrevious from 'sentry/utils/usePrevious';
3635

3736
interface FilterKeyListBoxProps<T> extends CustomComboboxMenuProps<T> {
@@ -80,30 +79,20 @@ function ListBoxSectionButton({
8079

8180
function FeedbackFooter() {
8281
const {searchSource} = useSearchQueryBuilder();
83-
const openForm = useFeedbackForm();
84-
85-
if (!openForm) {
86-
return null;
87-
}
8882

8983
return (
9084
<SectionedOverlayFooter>
91-
<Button
85+
<FeedbackButton
9286
size="xs"
93-
icon={<IconMegaphone />}
94-
onClick={() =>
95-
openForm({
96-
messagePlaceholder: t('How can we make search better for you?'),
97-
tags: {
98-
search_source: searchSource,
99-
['feedback.source']: 'search_query_builder',
100-
['feedback.owner']: 'issues',
101-
},
102-
})
103-
}
104-
>
105-
{t('Give Feedback')}
106-
</Button>
87+
feedbackOptions={{
88+
messagePlaceholder: t('How can we make search better for you?'),
89+
tags: {
90+
search_source: searchSource,
91+
['feedback.source']: 'search_query_builder',
92+
['feedback.owner']: 'issues',
93+
},
94+
}}
95+
/>
10796
</SectionedOverlayFooter>
10897
);
10998
}

static/app/views/alerts/rules/metric/details/sidebar.tsx

Lines changed: 16 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,18 @@ import {OnDemandWarningIcon} from 'sentry/components/alerts/onDemandMetricAlert'
66
import {SectionHeading} from 'sentry/components/charts/styles';
77
import {ActorAvatar} from 'sentry/components/core/avatar/actorAvatar';
88
import {AlertBadge} from 'sentry/components/core/badge/alertBadge';
9-
import {Button} from 'sentry/components/core/button';
109
import {DateTime} from 'sentry/components/dateTime';
1110
import Duration from 'sentry/components/duration';
11+
import FeedbackButton from 'sentry/components/feedbackButton/feedbackButton';
1212
import {KeyValueTable, KeyValueTableRow} from 'sentry/components/keyValueTable';
1313
import TimeSince from 'sentry/components/timeSince';
14-
import {IconDiamond, IconMegaphone} from 'sentry/icons';
14+
import {IconDiamond} from 'sentry/icons';
1515
import {t, tct} from 'sentry/locale';
1616
import {space} from 'sentry/styles/space';
1717
import type {Actor} from 'sentry/types/core';
1818
import {getSearchFilters, isOnDemandSearchKey} from 'sentry/utils/onDemandMetrics/index';
1919
import {capitalize} from 'sentry/utils/string/capitalize';
2020
import {isChonkTheme} from 'sentry/utils/theme/withChonk';
21-
import {useFeedbackForm} from 'sentry/utils/useFeedbackForm';
2221
import useOrganization from 'sentry/utils/useOrganization';
2322
import {COMPARISON_DELTA_OPTIONS} from 'sentry/views/alerts/rules/metric/constants';
2423
import type {Action, MetricRule} from 'sentry/views/alerts/rules/metric/types';
@@ -168,28 +167,22 @@ export function MetricDetailsSidebar({
168167

169168
const ownerId = rule.owner?.split(':')[1];
170169
const teamActor = ownerId && {type: 'team' as Actor['type'], id: ownerId, name: ''};
171-
const openForm = useFeedbackForm();
172-
173-
const feedbackButton = openForm ? (
174-
<Button
175-
onClick={() => {
176-
openForm({
177-
formTitle: 'Anomaly Detection Feedback',
178-
messagePlaceholder: t(
179-
'How can we make alerts using anomaly detection more useful?'
180-
),
181-
tags: {
182-
['feedback.source']: 'dynamic_thresholding',
183-
['feedback.owner']: 'ml-ai',
184-
},
185-
});
170+
171+
const feedbackButton = (
172+
<FeedbackButton
173+
feedbackOptions={{
174+
formTitle: t('Anomaly Detection Feedback'),
175+
messagePlaceholder: t(
176+
'How can we make alerts using anomaly detection more useful?'
177+
),
178+
tags: {
179+
['feedback.source']: 'dynamic_thresholding',
180+
['feedback.owner']: 'ml-ai',
181+
},
186182
}}
187183
size="xs"
188-
icon={<IconMegaphone />}
189-
>
190-
Give Feedback
191-
</Button>
192-
) : null;
184+
/>
185+
);
193186

194187
return (
195188
<Fragment>

0 commit comments

Comments
 (0)