diff --git a/app/assets/javascripts/app.ts b/app/assets/javascripts/app.ts
index dd0f8cb0a..32529da33 100644
--- a/app/assets/javascripts/app.ts
+++ b/app/assets/javascripts/app.ts
@@ -3,6 +3,7 @@
declare const __VERSION__: string;
declare const __WEB__: boolean;
+import { SNLog } from 'snjs';
import angular from 'angular';
import { configRoutes } from './routes';
@@ -53,6 +54,7 @@ import {
import { trusted } from './filters';
import { isDev } from './utils';
import { Bridge, BrowserBridge } from './services/bridge';
+import { startErrorReporting } from './services/errorReporting';
if (__WEB__) {
startApplication(
@@ -63,10 +65,14 @@ if (__WEB__) {
(window as any).startApplication = startApplication;
}
-function startApplication(
+async function startApplication(
defaultSyncServerHost: string,
bridge: Bridge
) {
+
+ SNLog.onLog = console.log;
+ startErrorReporting();
+
angular.module('app', ['ngSanitize']);
// Config
@@ -140,4 +146,8 @@ function startApplication(
},
});
}
+
+ angular.element(document).ready(() => {
+ angular.bootstrap(document, ['app']);
+ });
}
diff --git a/app/assets/javascripts/directives/views/accountMenu.ts b/app/assets/javascripts/directives/views/accountMenu.ts
index f09ba210a..2f38002cf 100644
--- a/app/assets/javascripts/directives/views/accountMenu.ts
+++ b/app/assets/javascripts/directives/views/accountMenu.ts
@@ -27,6 +27,7 @@ import { PasswordWizardType } from '@/types';
import { BackupFile } from 'snjs/dist/@types/services/protocol_service';
import { confirmDialog, alertDialog } from '@/services/alertService';
import { autorun, IReactionDisposer } from 'mobx';
+import { storage, StorageKey } from '@/services/localStorage';
const ELEMENT_ID_IMPORT_PASSWORD_INPUT = 'import-password-request';
@@ -65,6 +66,7 @@ type AccountMenuState = {
encryptionEnabled: boolean;
selectedAutoLockInterval: any;
showBetaWarning: boolean;
+ errorReportingEnabled: boolean;
}
class AccountMenuCtrl extends PureViewCtrl<{}, AccountMenuState> {
@@ -96,6 +98,7 @@ class AccountMenuCtrl extends PureViewCtrl<{}, AccountMenuState> {
},
mutable: {},
showBetaWarning: false,
+ errorReportingEnabled: !storage.get(StorageKey.DisableErrorReporting),
} as AccountMenuState;
}
@@ -587,6 +590,36 @@ class AccountMenuCtrl extends PureViewCtrl<{}, AccountMenuState> {
}
}
+ openErrorReportingDialog() {
+ alertDialog({
+ title: 'Data sent during automatic error reporting',
+ text: `
+ We use Bugsnag
+ to automatically report errors that occur while the app is running. See
+
+ this article, paragraph 'Browser' under 'Sending diagnostic data',
+
+ to see what data is included in error reports.
+
+ Error reports never include IP addresses and are fully
+ anonymized. We use error reports to be alerted when something in our
+ code is causing unexpected errors and crashes in your application
+ experience.
+ `
+ });
+ }
+
+ toggleErrorReportingEnabled() {
+ if (this.state.errorReportingEnabled) {
+ storage.set(StorageKey.DisableErrorReporting, true);
+ } else {
+ storage.set(StorageKey.DisableErrorReporting, false);
+ }
+ if (!this.application.getSyncStatus().syncInProgress) {
+ window.location.reload();
+ }
+ }
+
isDesktopApplication() {
return isDesktopApplication();
}
diff --git a/app/assets/javascripts/services/errorReporting.ts b/app/assets/javascripts/services/errorReporting.ts
new file mode 100644
index 000000000..83ffd015b
--- /dev/null
+++ b/app/assets/javascripts/services/errorReporting.ts
@@ -0,0 +1,33 @@
+import { SNLog } from 'snjs';
+import { isDesktopApplication, isDev } from '@/utils';
+import { storage, StorageKey } from './localStorage';
+import Bugsnag from '@bugsnag/js';
+
+declare const __VERSION__: string;
+
+export function startErrorReporting() {
+ if (storage.get(StorageKey.DisableErrorReporting)) {
+ SNLog.onError = console.error;
+ return;
+ }
+ try {
+ Bugsnag.start({
+ apiKey: (window as any)._bugsnag_api_key,
+ appType: isDesktopApplication() ? 'desktop' : 'web',
+ appVersion: __VERSION__,
+ collectUserIp: false,
+ autoTrackSessions: false,
+ releaseStage: isDev ? 'development' : undefined
+ });
+ if (isDev) {
+ SNLog.onError = console.error;
+ } else {
+ SNLog.onError = (error) => {
+ Bugsnag.notify(error);
+ }
+ }
+ } catch (error) {
+ console.error('Failed to start Bugsnag.', error);
+ SNLog.onError = console.error;
+ }
+}
diff --git a/app/assets/javascripts/services/localStorage.ts b/app/assets/javascripts/services/localStorage.ts
new file mode 100644
index 000000000..5f832ea00
--- /dev/null
+++ b/app/assets/javascripts/services/localStorage.ts
@@ -0,0 +1,16 @@
+export enum StorageKey {
+ DisableErrorReporting = 'DisableErrorReporting',
+}
+
+export const storage = {
+ get(key: StorageKey) {
+ const value = localStorage.getItem(key);
+ return value ? JSON.parse(value) : null;
+ },
+ set(key: StorageKey, value: unknown) {
+ localStorage.setItem(key, JSON.stringify(value));
+ },
+ remove(key: StorageKey) {
+ localStorage.removeItem(key);
+ },
+};
diff --git a/app/assets/templates/directives/account-menu.pug b/app/assets/templates/directives/account-menu.pug
index e55e232a0..799fa2c39 100644
--- a/app/assets/templates/directives/account-menu.pug
+++ b/app/assets/templates/directives/account-menu.pug
@@ -302,6 +302,18 @@
| the whole file, please use the Batch Manager extension.
.sk-panel-row
.sk-spinner.small.info(ng-if='self.state.importData.loading')
+ .sk-panel-section
+ .sk-panel-section-title Error Reporting
+ .sk-panel-section-subtitle.info
+ | Automatic error reporting is {{ self.state.errorReportingEnabled ? 'enabled.' : 'disabled.' }}
+ p.sk-p
+ | Help us improve Standard Notes by automatically submitting
+ | anonymized error reports.
+ .sk-panel-row
+ button(ng-click="self.toggleErrorReportingEnabled()").sk-button.info
+ span.sk-label {{ self.state.errorReportingEnabled ? 'Disable' : 'Enable'}} Error Reporting
+ .sk-panel-row
+ a(ng-click="self.openErrorReportingDialog()").sk-a What data is being sent?
.sk-panel-footer
.sk-panel-row
.sk-p.left.neutral
diff --git a/app/views/application/app.html.erb b/app/views/application/app.html.erb
index 724234545..39e70cf4c 100644
--- a/app/views/application/app.html.erb
+++ b/app/views/application/app.html.erb
@@ -1,5 +1,5 @@
-
+