-
-
Notifications
You must be signed in to change notification settings - Fork 4.1k
/
bootstrap.tsx
209 lines (182 loc) · 6.28 KB
/
bootstrap.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
/* global process */
import 'bootstrap/js/alert';
import 'bootstrap/js/tab';
import 'bootstrap/js/dropdown';
import 'focus-visible';
import 'app/utils/statics-setup';
import 'app/utils/emotion-setup';
import PropTypes from 'prop-types';
import React from 'react';
import ReactDOM from 'react-dom';
import Reflux from 'reflux';
import * as Router from 'react-router';
import SentryRRWeb from '@sentry/rrweb';
import createReactClass from 'create-react-class';
import jQuery from 'jquery';
import moment from 'moment';
import {Integrations} from '@sentry/apm';
import {ExtraErrorData} from '@sentry/integrations';
import * as Sentry from '@sentry/react';
import {metric} from 'app/utils/analytics';
import {init as initApiSentryClient} from 'app/utils/apiSentryClient';
import ConfigStore from 'app/stores/configStore';
import Main from 'app/main';
import ajaxCsrfSetup from 'app/utils/ajaxCsrfSetup';
import plugins from 'app/plugins';
import routes from 'app/routes';
import {normalizeTransactionName} from 'app/utils/apm';
if (process.env.NODE_ENV === 'development') {
import(
/* webpackChunkName: "SilenceReactUnsafeWarnings" */ /* webpackMode: "eager" */ 'app/utils/silence-react-unsafe-warnings'
);
}
// App setup
if (window.__initialData) {
ConfigStore.loadInitialData(window.__initialData);
if (window.__initialData.dsn_requests) {
initApiSentryClient(window.__initialData.dsn_requests);
}
}
// SDK INIT --------------------------------------------------------
const config = ConfigStore.getConfig();
const tracesSampleRate = config ? config.apmSampling : 0;
const appRoutes = Router.createRoutes(routes());
function getSentryIntegrations(hasReplays: boolean = false) {
const integrations = [
new ExtraErrorData({
// 6 is arbitrary, seems like a nice number
depth: 6,
}),
new Integrations.Tracing({
tracingOrigins: ['localhost', 'sentry.io', /^\//],
debug: {
spanDebugTimingInfo: true,
writeAsBreadcrumbs: true,
},
beforeNavigate: (location: Location) => {
return normalizeTransactionName(appRoutes, location);
},
}),
];
if (hasReplays) {
// eslint-disable-next-line no-console
console.log('[sentry] Instrumenting session with rrweb');
// TODO(ts): The type returned by SentryRRWeb seems to be somewhat
// incompatible. It's a newer plugin, so this can be expected, but we
// should fix.
integrations.push(
new SentryRRWeb({
checkoutEveryNms: 60 * 1000, // 60 seconds
}) as any
);
}
return integrations;
}
const hasReplays =
window.__SENTRY__USER && window.__SENTRY__USER.isStaff && !!process.env.DISABLE_RR_WEB;
Sentry.init({
...window.__SENTRY__OPTIONS,
/**
* For SPA mode, we need a way to overwrite the default DSN from backend
* as well as `whitelistUrls`
*/
dsn: process.env.SPA_DSN || window.__SENTRY__OPTIONS.dsn,
whitelistUrls: process.env.SPA_DSN
? ['localhost', 'dev.getsentry.net', 'sentry.dev', 'webpack-internal://']
: window.__SENTRY__OPTIONS.whitelistUrls,
integrations: getSentryIntegrations(hasReplays),
tracesSampleRate,
});
if (window.__SENTRY__USER) {
Sentry.setUser(window.__SENTRY__USER);
}
if (window.__SENTRY__VERSION) {
Sentry.setTag('sentry_version', window.__SENTRY__VERSION);
}
if (hasReplays) {
Sentry.setTag('rrweb.active', hasReplays ? 'yes' : 'no');
}
// Used for operational metrics to determine that the application js
// bundle was loaded by browser.
metric.mark({name: 'sentry-app-init'});
// setup jquery for CSRF tokens
jQuery.ajaxSetup({
//jQuery won't allow using the ajaxCsrfSetup function directly
beforeSend: ajaxCsrfSetup,
});
const render = (Component: React.ComponentType) => {
const rootEl = document.getElementById('blk_router');
try {
ReactDOM.render(<Component />, rootEl);
} catch (err) {
// eslint-disable-next-line no-console
console.error(
new Error(
'An unencoded "%" has appeared, it is super effective! (See https://github.com/ReactTraining/history/issues/505)'
)
);
if (err.message === 'URI malformed') {
window.location.assign(window.location.pathname);
}
}
};
// The password strength component is very heavyweight as it includes the
// zxcvbn, a relatively byte-heavy password strength estimation library. Load
// it on demand.
async function loadPasswordStrength(callback: Function) {
try {
const module = await import(
/* webpackChunkName: "passwordStrength" */ 'app/components/passwordStrength'
);
callback(module);
} catch (err) {
// Ignore if client can't load this, it enhances UX a bit, but is optional
}
}
const globals = {
// This is the primary entrypoint for rendering the sentry app.
SentryRenderApp: () => render(Main),
// The following globals are used in sentry-plugins webpack externals
// configuration.
PropTypes,
React,
Reflux,
Router,
Sentry,
moment,
ReactDOM: {
findDOMNode: ReactDOM.findDOMNode,
render: ReactDOM.render,
},
// jQuery is still exported to the window as some bootsrap functionality
// and legacy plugins like youtrack make use of it.
$: jQuery,
jQuery,
// django templates make use of these globals
createReactClass,
SentryApp: {},
};
// The SentryApp global contains exported app modules for use in javascript
// modules that are not compiled with the sentry bundle.
globals.SentryApp = {
// The following components are used in sentry-plugins.
Form: require('app/components/forms/form').default,
FormState: require('app/components/forms/index').FormState,
LoadingIndicator: require('app/components/loadingIndicator').default,
plugins: {
add: plugins.add,
addContext: plugins.addContext,
BasePlugin: plugins.BasePlugin,
DefaultIssuePlugin: plugins.DefaultIssuePlugin,
},
// The following components are used in legacy django HTML views
passwordStrength: {load: loadPasswordStrength},
U2fSign: require('app/components/u2f/u2fsign').default,
ConfigStore: require('app/stores/configStore').default,
SystemAlerts: require('app/views/app/systemAlerts').default,
Indicators: require('app/components/indicators').default,
SetupWizard: require('app/components/setupWizard').default,
};
// Make globals available on the window object
Object.keys(globals).forEach(name => (window[name] = globals[name]));
export default globals;