Skip to content

Commit 09e1cef

Browse files
authored
ref(browser): Streamline showReportDialog code (#16339)
Just a small refactor, noticed this while working on other browser sdk stuff. Moving this into a dedicated file decouples this from the core SDK functionality, which this IMHO is not (anymore). Also, we can streamline the code slightly for efficiency.
1 parent 760d006 commit 09e1cef

File tree

4 files changed

+70
-71
lines changed

4 files changed

+70
-71
lines changed

packages/browser/src/exports.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,8 @@ export {
8484
} from './stack-parsers';
8585
export { eventFromException, eventFromMessage, exceptionFromError } from './eventbuilder';
8686
export { createUserFeedbackEnvelope } from './userfeedback';
87-
export { getDefaultIntegrations, forceLoad, init, onLoad, showReportDialog } from './sdk';
87+
export { getDefaultIntegrations, forceLoad, init, onLoad } from './sdk';
88+
export { showReportDialog } from './report-dialog';
8889

8990
export { breadcrumbsIntegration } from './integrations/breadcrumbs';
9091
export { globalHandlersIntegration } from './integrations/globalhandlers';

packages/browser/src/report-dialog.ts

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import type { ReportDialogOptions } from '@sentry/core';
2+
import { getClient, getCurrentScope, getReportDialogEndpoint, lastEventId, logger } from '@sentry/core';
3+
import { DEBUG_BUILD } from './debug-build';
4+
import { WINDOW } from './helpers';
5+
6+
/**
7+
* Present the user with a report dialog.
8+
*
9+
* @param options Everything is optional, we try to fetch all info need from the current scope.
10+
*/
11+
export function showReportDialog(options: ReportDialogOptions = {}): void {
12+
const optionalDocument = WINDOW.document as Document | undefined;
13+
const injectionPoint = optionalDocument?.head || optionalDocument?.body;
14+
15+
// doesn't work without a document (React Native)
16+
if (!injectionPoint) {
17+
DEBUG_BUILD && logger.error('[showReportDialog] Global document not defined');
18+
return;
19+
}
20+
21+
const scope = getCurrentScope();
22+
const client = getClient();
23+
const dsn = client?.getDsn();
24+
25+
if (!dsn) {
26+
DEBUG_BUILD && logger.error('[showReportDialog] DSN not configured');
27+
return;
28+
}
29+
30+
const mergedOptions = {
31+
...options,
32+
user: {
33+
...scope.getUser(),
34+
...options.user,
35+
},
36+
eventId: options.eventId || lastEventId(),
37+
};
38+
39+
const script = WINDOW.document.createElement('script');
40+
script.async = true;
41+
script.crossOrigin = 'anonymous';
42+
script.src = getReportDialogEndpoint(dsn, mergedOptions);
43+
44+
const { onLoad, onClose } = mergedOptions;
45+
46+
if (onLoad) {
47+
script.onload = onLoad;
48+
}
49+
50+
if (onClose) {
51+
const reportDialogClosedMessageHandler = (event: MessageEvent): void => {
52+
if (event.data === '__sentry_reportdialog_closed__') {
53+
try {
54+
onClose();
55+
} finally {
56+
WINDOW.removeEventListener('message', reportDialogClosedMessageHandler);
57+
}
58+
}
59+
};
60+
WINDOW.addEventListener('message', reportDialogClosedMessageHandler);
61+
}
62+
63+
injectionPoint.appendChild(script);
64+
}

packages/browser/src/sdk.ts

Lines changed: 1 addition & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,12 @@
1-
import type { Client, Integration, Options, ReportDialogOptions } from '@sentry/core';
1+
import type { Client, Integration, Options } from '@sentry/core';
22
import {
33
consoleSandbox,
44
dedupeIntegration,
55
functionToStringIntegration,
6-
getCurrentScope,
76
getIntegrationsToSetup,
87
getLocationHref,
9-
getReportDialogEndpoint,
108
inboundFiltersIntegration,
119
initAndBind,
12-
lastEventId,
1310
logger,
1411
stackParserFromStackParserOptions,
1512
supportsFetch,
@@ -201,72 +198,6 @@ export function init(browserOptions: BrowserOptions = {}): Client | undefined {
201198
return initAndBind(BrowserClient, clientOptions);
202199
}
203200

204-
/**
205-
* Present the user with a report dialog.
206-
*
207-
* @param options Everything is optional, we try to fetch all info need from the global scope.
208-
*/
209-
export function showReportDialog(options: ReportDialogOptions = {}): void {
210-
// doesn't work without a document (React Native)
211-
if (!WINDOW.document) {
212-
DEBUG_BUILD && logger.error('Global document not defined in showReportDialog call');
213-
return;
214-
}
215-
216-
const scope = getCurrentScope();
217-
const client = scope.getClient();
218-
const dsn = client?.getDsn();
219-
220-
if (!dsn) {
221-
DEBUG_BUILD && logger.error('DSN not configured for showReportDialog call');
222-
return;
223-
}
224-
225-
if (scope) {
226-
options.user = {
227-
...scope.getUser(),
228-
...options.user,
229-
};
230-
}
231-
232-
if (!options.eventId) {
233-
const eventId = lastEventId();
234-
if (eventId) {
235-
options.eventId = eventId;
236-
}
237-
}
238-
239-
const script = WINDOW.document.createElement('script');
240-
script.async = true;
241-
script.crossOrigin = 'anonymous';
242-
script.src = getReportDialogEndpoint(dsn, options);
243-
244-
if (options.onLoad) {
245-
script.onload = options.onLoad;
246-
}
247-
248-
const { onClose } = options;
249-
if (onClose) {
250-
const reportDialogClosedMessageHandler = (event: MessageEvent): void => {
251-
if (event.data === '__sentry_reportdialog_closed__') {
252-
try {
253-
onClose();
254-
} finally {
255-
WINDOW.removeEventListener('message', reportDialogClosedMessageHandler);
256-
}
257-
}
258-
};
259-
WINDOW.addEventListener('message', reportDialogClosedMessageHandler);
260-
}
261-
262-
const injectionPoint = WINDOW.document.head || WINDOW.document.body;
263-
if (injectionPoint) {
264-
injectionPoint.appendChild(script);
265-
} else {
266-
DEBUG_BUILD && logger.error('Not injecting report dialog. No injection point found in HTML');
267-
}
268-
}
269-
270201
/**
271202
* This function is here to be API compatible with the loader.
272203
* @hidden

packages/browser/test/tracing/browserTracingIntegration.test.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ describe('browserTracingIntegration', () => {
7171
getIsolationScope().clear();
7272
getCurrentScope().setClient(undefined);
7373
document.head.innerHTML = '';
74+
75+
// We want to suppress the "Multiple browserTracingIntegration instances are not supported." warnings
76+
vi.spyOn(console, 'warn').mockImplementation(() => {});
7477
});
7578

7679
afterEach(() => {

0 commit comments

Comments
 (0)