Skip to content

Commit 373ee88

Browse files
authored
Merge branch 'develop' into cg/streamed-span-op-attribute
2 parents 623ad14 + b045541 commit 373ee88

13 files changed

Lines changed: 243 additions & 43 deletions

File tree

.size-limit.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ module.exports = [
103103
path: 'packages/browser/build/npm/esm/prod/index.js',
104104
import: createImport('init', 'feedbackIntegration'),
105105
gzip: true,
106-
limit: '43 KB',
106+
limit: '44 KB',
107107
},
108108
{
109109
name: '@sentry/browser (incl. sendFeedback)',
@@ -233,7 +233,7 @@ module.exports = [
233233
name: 'CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics)',
234234
path: createCDNPath('bundle.tracing.replay.feedback.logs.metrics.min.js'),
235235
gzip: true,
236-
limit: '90.5 KB',
236+
limit: '91 KB',
237237
},
238238
// browser CDN bundles (non-gzipped)
239239
{
@@ -297,7 +297,7 @@ module.exports = [
297297
path: createCDNPath('bundle.tracing.replay.feedback.logs.metrics.min.js'),
298298
gzip: false,
299299
brotli: false,
300-
limit: '273.5 KB',
300+
limit: '273 KB',
301301
},
302302
// Next.js SDK (ESM)
303303
{

packages/core/src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,8 @@ export type {
453453
ReplayStopReason,
454454
} from './types-hoist/replay';
455455
export type {
456+
FeedbackErrorCode,
457+
FeedbackErrorMessages,
456458
FeedbackEvent,
457459
FeedbackFormData,
458460
FeedbackInternalOptions,

packages/core/src/types-hoist/feedback/config.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,31 @@ export interface FeedbackTextConfiguration {
191191
* The label for the button that removed a highlight/hidden section of the screenshot.
192192
*/
193193
removeHighlightText: string;
194+
195+
/**
196+
* Error text shown when feedback submission is attempted with an empty message
197+
*/
198+
errorEmptyMessageText: string;
199+
200+
/**
201+
* Error text shown when the Sentry client is not set up
202+
*/
203+
errorNoClientText: string;
204+
205+
/**
206+
* Error text shown when the feedback submission times out (after 30s)
207+
*/
208+
errorTimeoutText: string;
209+
210+
/**
211+
* Error text shown when the feedback submission is blocked because the domain is not allowed (HTTP 403)
212+
*/
213+
errorForbiddenText: string;
214+
215+
/**
216+
* Error text shown when the feedback submission fails for any other reason (e.g. network error, ad-blocker)
217+
*/
218+
errorGenericText: string;
194219
}
195220

196221
/**

packages/core/src/types-hoist/feedback/index.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,17 @@ import type {
66
FeedbackTextConfiguration,
77
FeedbackThemeConfiguration,
88
} from './config';
9-
import type { FeedbackEvent, SendFeedback, SendFeedbackParams, UserFeedback } from './sendFeedback';
9+
import type {
10+
FeedbackErrorCode,
11+
FeedbackErrorMessages,
12+
FeedbackEvent,
13+
SendFeedback,
14+
SendFeedbackParams,
15+
UserFeedback,
16+
} from './sendFeedback';
1017

1118
export type { FeedbackFormData } from './form';
12-
export type { FeedbackEvent, UserFeedback, SendFeedback, SendFeedbackParams };
19+
export type { FeedbackErrorCode, FeedbackErrorMessages, FeedbackEvent, SendFeedback, SendFeedbackParams, UserFeedback };
1320

1421
/**
1522
* The integration's internal `options` member where every value should be set

packages/core/src/types-hoist/feedback/sendFeedback.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,16 @@ export interface SendFeedbackParams {
4747
tags?: { [key: string]: Primitive };
4848
}
4949

50+
export type FeedbackErrorCode =
51+
| 'ERROR_EMPTY_MESSAGE'
52+
| 'ERROR_NO_CLIENT'
53+
| 'ERROR_TIMEOUT'
54+
| 'ERROR_FORBIDDEN'
55+
| 'ERROR_GENERIC';
56+
57+
export type FeedbackErrorMessages = Partial<Record<FeedbackErrorCode, string>>;
58+
5059
export type SendFeedback = (
5160
params: SendFeedbackParams,
52-
hint?: EventHint & { includeReplay?: boolean },
61+
hint?: EventHint & { includeReplay?: boolean; errorMessages?: FeedbackErrorMessages },
5362
) => Promise<string>;

packages/feedback/src/constants/index.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,14 @@ export const HIGHLIGHT_TOOL_TEXT = 'Highlight';
2626
export const HIDE_TOOL_TEXT = 'Hide';
2727
export const REMOVE_HIGHLIGHT_TEXT = 'Remove';
2828

29+
export const ERROR_EMPTY_MESSAGE_TEXT = 'Unable to submit feedback with empty message';
30+
export const ERROR_NO_CLIENT_TEXT = 'No client setup, cannot send feedback.';
31+
export const ERROR_TIMEOUT_TEXT = 'Unable to determine if Feedback was correctly sent.';
32+
export const ERROR_FORBIDDEN_TEXT =
33+
'Unable to send feedback. This could be because this domain is not in your list of allowed domains.';
34+
export const ERROR_GENERIC_TEXT =
35+
'Unable to send feedback. This could be because of network issues, or because you are using an ad-blocker.';
36+
2937
export const FEEDBACK_WIDGET_SOURCE = 'widget';
3038
export const FEEDBACK_API_SOURCE = 'api';
3139

packages/feedback/src/core/integration.ts

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
/* eslint-disable max-lines */
2+
/* eslint-disable complexity */
23

34
import type {
5+
FeedbackErrorMessages,
46
FeedbackInternalOptions,
57
FeedbackModalIntegration,
68
FeedbackScreenshotIntegration,
79
Integration,
810
IntegrationFn,
11+
SendFeedback,
912
} from '@sentry/core';
1013
import { addIntegration, debug, isBrowser } from '@sentry/core';
1114
import {
@@ -15,6 +18,11 @@ import {
1518
DOCUMENT,
1619
EMAIL_LABEL,
1720
EMAIL_PLACEHOLDER,
21+
ERROR_EMPTY_MESSAGE_TEXT,
22+
ERROR_FORBIDDEN_TEXT,
23+
ERROR_GENERIC_TEXT,
24+
ERROR_NO_CLIENT_TEXT,
25+
ERROR_TIMEOUT_TEXT,
1826
FORM_TITLE,
1927
HIDE_TOOL_TEXT,
2028
HIGHLIGHT_TOOL_TEXT,
@@ -119,6 +127,11 @@ export const buildFeedbackIntegration = ({
119127
highlightToolText = HIGHLIGHT_TOOL_TEXT,
120128
hideToolText = HIDE_TOOL_TEXT,
121129
removeHighlightText = REMOVE_HIGHLIGHT_TEXT,
130+
errorEmptyMessageText = ERROR_EMPTY_MESSAGE_TEXT,
131+
errorNoClientText = ERROR_NO_CLIENT_TEXT,
132+
errorTimeoutText = ERROR_TIMEOUT_TEXT,
133+
errorForbiddenText = ERROR_FORBIDDEN_TEXT,
134+
errorGenericText = ERROR_GENERIC_TEXT,
122135

123136
// FeedbackCallbacks
124137
onFormOpen,
@@ -164,6 +177,11 @@ export const buildFeedbackIntegration = ({
164177
highlightToolText,
165178
hideToolText,
166179
removeHighlightText,
180+
errorEmptyMessageText,
181+
errorNoClientText,
182+
errorTimeoutText,
183+
errorForbiddenText,
184+
errorGenericText,
167185

168186
onFormClose,
169187
onFormOpen,
@@ -230,6 +248,16 @@ export const buildFeedbackIntegration = ({
230248
debug.error('[Feedback] Missing feedback screenshot integration. Proceeding without screenshots.');
231249
}
232250

251+
const errorMessages: FeedbackErrorMessages = {
252+
ERROR_EMPTY_MESSAGE: options.errorEmptyMessageText,
253+
ERROR_NO_CLIENT: options.errorNoClientText,
254+
ERROR_TIMEOUT: options.errorTimeoutText,
255+
ERROR_FORBIDDEN: options.errorForbiddenText,
256+
ERROR_GENERIC: options.errorGenericText,
257+
};
258+
const wrappedSendFeedback: SendFeedback = (params, hint) =>
259+
sendFeedback(params, { includeReplay: true, ...hint, errorMessages });
260+
233261
const dialog = modalIntegration.createDialog({
234262
options: {
235263
...options,
@@ -243,7 +271,7 @@ export const buildFeedbackIntegration = ({
243271
},
244272
},
245273
screenshotIntegration,
246-
sendFeedback,
274+
sendFeedback: wrappedSendFeedback,
247275
shadow: _createShadow(options),
248276
});
249277

packages/feedback/src/core/sendFeedback.ts

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,33 @@
1-
import type { Event, EventHint, SendFeedback, SendFeedbackParams, TransportMakeRequestResponse } from '@sentry/core';
1+
import type {
2+
Event,
3+
EventHint,
4+
FeedbackErrorMessages,
5+
SendFeedback,
6+
SendFeedbackParams,
7+
TransportMakeRequestResponse,
8+
} from '@sentry/core';
29
import { captureFeedback, getClient, getCurrentScope, getLocationHref } from '@sentry/core';
310
import { FEEDBACK_API_SOURCE } from '../constants';
11+
import { createFeedbackError, resolveFeedbackErrorMessage } from '../util/createFeedbackError';
412

513
/**
614
* Public API to send a Feedback item to Sentry
715
*/
816
export const sendFeedback: SendFeedback = (
917
params: SendFeedbackParams,
10-
hint: EventHint & { includeReplay?: boolean } = { includeReplay: true },
18+
hint: EventHint & { includeReplay?: boolean; errorMessages?: FeedbackErrorMessages } = { includeReplay: true },
1119
): Promise<string> => {
20+
const errorMessages = hint.errorMessages;
21+
1222
if (!params.message) {
13-
throw new Error('Unable to submit feedback with empty message');
23+
throw createFeedbackError('ERROR_EMPTY_MESSAGE', errorMessages);
1424
}
1525

1626
// We want to wait for the feedback to be sent (or not)
1727
const client = getClient();
1828

1929
if (!client) {
20-
throw new Error('No client setup, cannot send feedback.');
30+
throw createFeedbackError('ERROR_NO_CLIENT', errorMessages);
2131
}
2232

2333
if (params.tags && Object.keys(params.tags).length) {
@@ -35,7 +45,10 @@ export const sendFeedback: SendFeedback = (
3545
// We want to wait for the feedback to be sent (or not)
3646
return new Promise<string>((resolve, reject) => {
3747
// After 30s, we want to clear anyhow
38-
const timeout = setTimeout(() => reject('Unable to determine if Feedback was correctly sent.'), 30_000);
48+
const timeout = setTimeout(() => {
49+
cleanup();
50+
reject(resolveFeedbackErrorMessage('ERROR_TIMEOUT', errorMessages));
51+
}, 30_000);
3952

4053
const cleanup = client.on('afterSendEvent', (event: Event, response: TransportMakeRequestResponse) => {
4154
if (event.event_id !== eventId) {
@@ -51,14 +64,10 @@ export const sendFeedback: SendFeedback = (
5164
}
5265

5366
if (response?.statusCode === 403) {
54-
return reject(
55-
'Unable to send feedback. This could be because this domain is not in your list of allowed domains.',
56-
);
67+
return reject(resolveFeedbackErrorMessage('ERROR_FORBIDDEN', errorMessages));
5768
}
5869

59-
return reject(
60-
'Unable to send feedback. This could be because of network issues, or because you are using an ad-blocker.',
61-
);
70+
return reject(resolveFeedbackErrorMessage('ERROR_GENERIC', errorMessages));
6271
});
6372
});
6473
};

packages/feedback/src/modal/components/Form.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,8 +131,9 @@ export function Form({
131131
onSubmitSuccess(data, eventId);
132132
} catch (error) {
133133
DEBUG_BUILD && debug.error(error);
134-
setError(error as string);
135-
onSubmitError(error as Error);
134+
const err = error instanceof Error ? error : new Error(String(error));
135+
setError(err.message);
136+
onSubmitError(err);
136137
}
137138
} finally {
138139
setIsSubmitting(false);
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import type { FeedbackErrorCode, FeedbackErrorMessages } from '@sentry/core';
2+
import {
3+
ERROR_EMPTY_MESSAGE_TEXT,
4+
ERROR_FORBIDDEN_TEXT,
5+
ERROR_GENERIC_TEXT,
6+
ERROR_NO_CLIENT_TEXT,
7+
ERROR_TIMEOUT_TEXT,
8+
} from '../constants';
9+
10+
const DEFAULT_MESSAGES: Record<FeedbackErrorCode, string> = {
11+
ERROR_EMPTY_MESSAGE: ERROR_EMPTY_MESSAGE_TEXT,
12+
ERROR_NO_CLIENT: ERROR_NO_CLIENT_TEXT,
13+
ERROR_TIMEOUT: ERROR_TIMEOUT_TEXT,
14+
ERROR_FORBIDDEN: ERROR_FORBIDDEN_TEXT,
15+
ERROR_GENERIC: ERROR_GENERIC_TEXT,
16+
};
17+
18+
export function resolveFeedbackErrorMessage(code: FeedbackErrorCode, messages?: FeedbackErrorMessages): string {
19+
return messages?.[code] ?? DEFAULT_MESSAGES[code];
20+
}
21+
22+
export function createFeedbackError(code: FeedbackErrorCode, messages?: FeedbackErrorMessages): Error {
23+
return new Error(resolveFeedbackErrorMessage(code, messages));
24+
}

0 commit comments

Comments
 (0)