Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
151 changes: 151 additions & 0 deletions src/sentry/static/sentry/app/bootstrap.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
import 'bootstrap/js/alert';
Comment thread
BYK marked this conversation as resolved.
Outdated
import 'bootstrap/js/tab';
import 'bootstrap/js/dropdown';

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 * as Sentry from '@sentry/browser';
import {ExtraErrorData, Tracing} from '@sentry/integrations';
import createReactClass from 'create-react-class';
import jQuery from 'jquery';
import moment from 'moment';

import {metric} from 'app/utils/analytics';
import ConfigStore from 'app/stores/configStore';
import Main from 'app/main';
import ajaxCsrfSetup from 'app/utils/ajaxCsrfSetup';
import plugins from 'app/plugins';

// SDK INIT --------------------------------------------------------
Sentry.init({
...window.__SENTRY__OPTIONS,
integrations: [
new ExtraErrorData({
// 6 is arbitrary, seems like a nice number
depth: 6,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: move this to a const or make it configurable from the API?

}),
new Tracing({
tracingOrigins: ['localhost', 'sentry.io', /^\//],
Comment thread
BYK marked this conversation as resolved.
Outdated
autoStartOnDomReady: false,
}),
],
});

Sentry.configureScope(scope => {
if (window.__SENTRY__USER) {
scope.setUser(window.__SENTRY__USER);
}
if (window.__SENTRY__VERSION) {
scope.setTag('sentry_version', window.__SENTRY__VERSION);
}
});

// -----------------------------------------------------------------

// Used for operational metrics to determine that the application js
// bundle was loaded by browser.
metric.mark('sentry-app-init');

// setup jquery for CSRF tokens
jQuery.ajaxSetup({
//jQuery won't allow using the ajaxCsrfSetup function directly
beforeSend: ajaxCsrfSetup,
});

// App setup
if (window.__initialData) {
ConfigStore.loadInitialData(window.__initialData);
}

// these get exported to a global variable, which is important as its the only
// way we can call into scoped objects

const render = Component => {
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) {
const module = await import(/* webpackChunkName: "passwordStrength" */ 'app/components/passwordStrength');
callback(module);
}

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
// makes use of it.
$: jQuery,
jQuery,

// django templates make use of these globals
createReactClass,
};

// The SentryApp global contains exported app modules for use in javascript

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// The SentryApp global contains exported app modules for use in javascript
// The SentryApp global contains exported app modules for use in JavaScript

:trollface:

// modules that are not compiled with the sentry bundle.
globals.SentryApp = {
Comment thread
BYK marked this conversation as resolved.
// 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,
Alerts: require('app/components/alerts').default,
Indicators: require('app/components/indicators').default,
ProjectSelector: require('app/components/projectHeader/projectSelector').default,
Sidebar: require('app/components/sidebar').default,
SetupWizard: require('app/components/setupWizard').default,
OrganizationsLoader: require('app/components/organizations/organizationsLoader')
.default,
};

// Make globals available on the window object
Object.keys(globals).forEach(name => (window[name] = globals[name]));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

eww


export default globals;
156 changes: 9 additions & 147 deletions src/sentry/static/sentry/app/index.js
Original file line number Diff line number Diff line change
@@ -1,153 +1,15 @@
import '@babel/polyfill';
import 'bootstrap/js/alert';
import 'bootstrap/js/tab';
import 'bootstrap/js/dropdown';

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 * as Sentry from '@sentry/browser';
import {ExtraErrorData, Tracing} from '@sentry/integrations';
import createReactClass from 'create-react-class';
import jQuery from 'jquery';
import moment from 'moment';

import {metric} from 'app/utils/analytics';
import ConfigStore from 'app/stores/configStore';
import Main from 'app/main';
import ajaxCsrfSetup from 'app/utils/ajaxCsrfSetup';
import plugins from 'app/plugins';

// SDK INIT --------------------------------------------------------
// window.__SENTRY__OPTIONS will be emmited by sdk-config.html before loading this script
Sentry.init({
...window.__SENTRY__OPTIONS,
integrations: [
new ExtraErrorData({
// 6 is arbitrary, seems like a nice number
depth: 6,
}),
new Tracing({
tracingOrigins: ['localhost', 'sentry.io', /^\//],
autoStartOnDomReady: false,
}),
],
});

Sentry.configureScope(scope => {
if (window.__SENTRY__USER) {
scope.setUser(window.__SENTRY__USER);
}
if (window.__SENTRY__VERSION) {
scope.setTag('sentry_version', window.__SENTRY__VERSION);
}
});

// -----------------------------------------------------------------

// Used for operational metrics to determine that the application js
// bundle was loaded by browser.
metric.mark('sentry-app-init');

// setup jquery for CSRF tokens
jQuery.ajaxSetup({
//jQuery won't allow using the ajaxCsrfSetup function directly
beforeSend: ajaxCsrfSetup,
});

// App setup
// Initial data hydration. The __initialData will be set by the django backend
// serving sentry.
Comment thread
BYK marked this conversation as resolved.
Outdated
if (window.__initialData) {
ConfigStore.loadInitialData(window.__initialData, window.__languageCode);
}

// these get exported to a global variable, which is important as its the only
// way we can call into scoped objects
const {distPrefix, csrfCookieName, sentryConfig, userIdentity} = window.__initialData;

const render = Component => {
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) {
const module = await import(/* webpackChunkName: "passwordStrength" */ 'app/components/passwordStrength');
callback(module);
window.csrfCookieName = csrfCookieName;
window.__sentryGlobalStaticPrefix = distPrefix;
window.__SENTRY__OPTIONS = sentryConfig;
window.__SENTRY__USER = userIdentity;
}

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
// makes use of it.
$: jQuery,
jQuery,

// django templates make use of these globals
createReactClass,
};

// 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,
Alerts: require('app/components/alerts').default,
Indicators: require('app/components/indicators').default,
ProjectSelector: require('app/components/projectHeader/projectSelector').default,
Sidebar: require('app/components/sidebar').default,
SetupWizard: require('app/components/setupWizard').default,
OrganizationsLoader: require('app/components/organizations/organizationsLoader')
.default,
};

// Make globals available on the window object
Object.keys(globals).forEach(name => (window[name] = globals[name]));

export default globals;
// Once data hydration is done we can initialize the app
require('app/bootstrap');
Comment thread
BYK marked this conversation as resolved.
17 changes: 9 additions & 8 deletions src/sentry/static/sentry/app/stores/configStore.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,13 @@ const ConfigStore = Reflux.createStore({
return this.config;
},

loadInitialData(config, languageOverride = null) {
loadInitialData(config) {
config.features = new Set(config.features || []);
this.config = config;

// Language code is passed from django
let languageCode = config.languageCode;

// TODO(dcramer): abstract this out of ConfigStore
if (config.user) {
config.user.permissions = new Set(config.user.permissions);
Expand All @@ -43,15 +46,13 @@ const ConfigStore = Reflux.createStore({
// e.g. unencoded "%"
}

// Priority:
// "?lang=en" --> user configuration options --> django request.LANGUAGE_CODE --> "en"
setLocale(
queryString.lang || config.user.options.language || languageOverride || 'en'
);
} else if (languageOverride) {
setLocale(languageOverride);
languageCode = queryString.lang || config.user.options.language || languageCode;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: see if we can also leverage navigator.language as a last resort.

}

// Priority:
// "?lang=en" --> user configuration options --> django request.LANGUAGE_CODE --> "en"
setLocale(languageCode || 'en');

this.trigger(config);
},
});
Expand Down
Empty file.
4 changes: 0 additions & 4 deletions src/sentry/templates/sentry/layout.html
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,10 @@
<title>{% block title %}Sentry{% endblock %}</title>

<script>
window.csrfCookieName = '{{ CSRF_COOKIE_NAME }}';
window.__sentryGlobalStaticPrefix = '{% asset_url "sentry" "dist/" %}';
window.__initialData = {% get_react_config %};
window.__languageCode = {{ request.LANGUAGE_CODE|to_json|safe }};
</script>

{% block scripts %}
{% include "sentry/includes/sdk-config.html" %}
{% locale_js_include %}
<script src="{% asset_url "sentry" "dist/vendor.js" %}"{% crossorigin %}></script>
<script src="{% asset_url "sentry" "dist/app.js" %}"{% crossorigin %}></script>
Expand Down
Loading