From a15056d8409cc21ae0003a1fe6ff39e583efe6c9 Mon Sep 17 00:00:00 2001
From: Denis Davidyuk
Date: Tue, 13 Jul 2021 05:53:26 +0300
Subject: [PATCH 1/6] refactor(AlertModal): reuse AeButton
---
src/components/AlertModal.vue | 21 ++++-----------------
1 file changed, 4 insertions(+), 17 deletions(-)
diff --git a/src/components/AlertModal.vue b/src/components/AlertModal.vue
index 8dc284422..850253236 100644
--- a/src/components/AlertModal.vue
+++ b/src/components/AlertModal.vue
@@ -16,12 +16,9 @@
>
{{ row }}
-
+
@@ -30,8 +27,10 @@
diff --git a/src/components/Dialog.vue b/src/components/Dialog.vue
new file mode 100644
index 000000000..1e1fea444
--- /dev/null
+++ b/src/components/Dialog.vue
@@ -0,0 +1,68 @@
+
+
+
+
+
+
+
+
From af9b3988027a3d85af95b3ae0e1c9dcf42d95642 Mon Sep 17 00:00:00 2001
From: Yury Shapkarin
Date: Thu, 1 Apr 2021 16:01:29 +0300
Subject: [PATCH 4/6] feat: global error handler, ErrorReportModal
---
package-lock.json | 15 ++
package.json | 1 +
src/assets/iconCodeError.svg | 28 ++++
src/assets/iconThumbUp.svg | 33 +++++
src/components/Dialog.vue | 61 +++++++-
src/components/ErrorReportModal.vue | 139 +++++++++++++++++++
src/components/ErrorReportSubmittedModal.vue | 35 +++++
src/locales/en.json | 16 +++
src/locales/es.json | 16 +++
src/locales/fr.json | 16 +++
src/locales/zh.json | 16 +++
src/store/index.js | 2 +
src/store/plugins/errorHandler.js | 54 +++++++
src/utils/backend.js | 8 ++
src/views/modals.js | 12 ++
15 files changed, 446 insertions(+), 6 deletions(-)
create mode 100644 src/assets/iconCodeError.svg
create mode 100644 src/assets/iconThumbUp.svg
create mode 100644 src/components/ErrorReportModal.vue
create mode 100644 src/components/ErrorReportSubmittedModal.vue
create mode 100644 src/store/plugins/errorHandler.js
diff --git a/package-lock.json b/package-lock.json
index 37d98b6c8..2bf11ed21 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -19359,6 +19359,21 @@
}
}
},
+ "serialize-error": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-8.1.0.tgz",
+ "integrity": "sha512-3NnuWfM6vBYoy5gZFvHiYsVbafvI9vZv/+jlIigFn4oP4zjNPK3LhcY0xSCgeb1a5L8jO71Mit9LlNoi2UfDDQ==",
+ "requires": {
+ "type-fest": "^0.20.2"
+ },
+ "dependencies": {
+ "type-fest": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
+ "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ=="
+ }
+ }
+ },
"serialize-javascript": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz",
diff --git a/package.json b/package.json
index fcd92f8b5..5fdc0a8cb 100644
--- a/package.json
+++ b/package.json
@@ -48,6 +48,7 @@
"lru-cache": "^6.0.0",
"node-fetch": "^2.6.1",
"normalize.css": "^8.0.1",
+ "serialize-error": "^8.1.0",
"serve-static": "^1.14.1",
"sophia-bonding-curve": "github:aeternity/BondingCurve#1.0.0-alpha.2",
"soundcloud-widget": "^0.2.1",
diff --git a/src/assets/iconCodeError.svg b/src/assets/iconCodeError.svg
new file mode 100644
index 000000000..45dc8f973
--- /dev/null
+++ b/src/assets/iconCodeError.svg
@@ -0,0 +1,28 @@
+
+
+
diff --git a/src/assets/iconThumbUp.svg b/src/assets/iconThumbUp.svg
new file mode 100644
index 000000000..d636e2a6f
--- /dev/null
+++ b/src/assets/iconThumbUp.svg
@@ -0,0 +1,33 @@
+
+
+
diff --git a/src/components/Dialog.vue b/src/components/Dialog.vue
index 1e1fea444..266262b0b 100644
--- a/src/components/Dialog.vue
+++ b/src/components/Dialog.vue
@@ -5,6 +5,13 @@
@click.self="$emit('close')"
>
{{ title }}
+
+ {{ subtitle }}
+
@@ -40,29 +55,63 @@ export default {
text-align: center;
width: 25rem;
margin: auto;
- padding: 2.5rem;
+ padding: 40px 32px;
background-color: $actions_ribbon_background_color;
border-radius: 0.25rem;
border: 1px solid $card_border_color;
box-shadow: 4px 4px 8px rgba(0, 0, 0, 0.25);
+ font-size: 15px;
+ line-height: 24px;
+ color: $tip_note_color;
+ position: relative;
@include smallest {
width: 100%;
padding: 1rem;
}
+ .close {
+ position: absolute;
+ top: 8px;
+ right: 8px;
+ color: $light_font_color;
+
+ &:hover {
+ color: #fff;
+ }
+
+ svg {
+ height: 32px;
+ }
+ }
+
.icon {
- img, svg {
- height: 2rem;
- margin-bottom: 0.85rem;
+ img,
+ svg {
+ display: block;
+ margin: 0 auto 8px auto;
+ height: 48px;
}
}
- h1 {
+ h1,
+ h2 {
+ margin-top: 0;
color: $standard_font_color;
- font-size: 1rem;
font-weight: 500;
}
+
+ h1 {
+ font-size: 19px;
+ line-height: 22px;
+ margin-bottom: 24px;
+ }
+
+ h2 {
+ font-size: 15px;
+ line-height: 24px;
+ margin-bottom: 8px;
+ }
}
}
diff --git a/src/components/ErrorReportModal.vue b/src/components/ErrorReportModal.vue
new file mode 100644
index 000000000..c1a206afa
--- /dev/null
+++ b/src/components/ErrorReportModal.vue
@@ -0,0 +1,139 @@
+
+
+
+
+
+
+
diff --git a/src/components/ErrorReportSubmittedModal.vue b/src/components/ErrorReportSubmittedModal.vue
new file mode 100644
index 000000000..9ba09ebad
--- /dev/null
+++ b/src/components/ErrorReportSubmittedModal.vue
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
diff --git a/src/locales/en.json b/src/locales/en.json
index 63f47231b..70620f2f8 100644
--- a/src/locales/en.json
+++ b/src/locales/en.json
@@ -651,5 +651,21 @@
"MenuLink": "Meet",
"Placeholder": "Room name",
"Start": "Start"
+ },
+ "reportBug": {
+ "Title": "Unhandled error",
+ "SubTitle": "Would you like to submit a bug report?",
+ "TechnicalDetails": "Technical details",
+ "Description": "We have encountered an error while loading this page. Be a fellow superhero and help us improve our service by sending us a bug report. Only technical details and no personal data will be submitted.",
+ "DescriptionTitle": "Bug description",
+ "Send": "Submit",
+ "Cancel": "Cancel",
+ "Placeholder": "Describe the bug you encountered (optional)",
+ "Success": {
+ "Title": "Thank you!",
+ "SubTitle": "Your bug report has been submitted.",
+ "Description": "Thank you for being such a wonderful fellow superhero. The information provided will help us to improve our product and services for the benefit of the whole Superhero community.",
+ "Return": "Return to website"
+ }
}
}
diff --git a/src/locales/es.json b/src/locales/es.json
index 30c2b914c..d5650f723 100644
--- a/src/locales/es.json
+++ b/src/locales/es.json
@@ -647,5 +647,21 @@
"MenuLink": "Encontrar",
"Placeholder": "Nombre de la habitación",
"Start": "Empieza"
+ },
+ "reportBug": {
+ "Title": "Unhandled error",
+ "SubTitle": "Would you like to submit a bug report?",
+ "TechnicalDetails": "Technical details",
+ "Description": "We have encountered an error while loading this page. Be a fellow superhero and help us improve our service by sending us a bug report. Only technical details and no personal data will be submitted.",
+ "DescriptionTitle": "Bug description",
+ "Send": "Submit",
+ "Cancel": "Cancel",
+ "Placeholder": "Describe the bug you encountered (optional)",
+ "Success": {
+ "Title": "Thank you!",
+ "SubTitle": "Your bug report has been submitted.",
+ "Description": "Thank you for being such a wonderful fellow superhero. The information provided will help us to improve our product and services for the benefit of the whole Superhero community.",
+ "Return": "Return to website"
+ }
}
}
diff --git a/src/locales/fr.json b/src/locales/fr.json
index 612b62518..c7426761d 100644
--- a/src/locales/fr.json
+++ b/src/locales/fr.json
@@ -637,5 +637,21 @@
"MenuLink": "Rencontrer",
"Placeholder": "Nom de la pièce",
"Start": "Commencer"
+ },
+ "reportBug": {
+ "Title": "Unhandled error",
+ "SubTitle": "Would you like to submit a bug report?",
+ "TechnicalDetails": "Technical details",
+ "Description": "We have encountered an error while loading this page. Be a fellow superhero and help us improve our service by sending us a bug report. Only technical details and no personal data will be submitted.",
+ "DescriptionTitle": "Bug description",
+ "Send": "Submit",
+ "Cancel": "Cancel",
+ "Placeholder": "Describe the bug you encountered (optional)",
+ "Success": {
+ "Title": "Thank you!",
+ "SubTitle": "Your bug report has been submitted.",
+ "Description": "Thank you for being such a wonderful fellow superhero. The information provided will help us to improve our product and services for the benefit of the whole Superhero community.",
+ "Return": "Return to website"
+ }
}
}
diff --git a/src/locales/zh.json b/src/locales/zh.json
index 35ac40ed5..7e1429b9c 100644
--- a/src/locales/zh.json
+++ b/src/locales/zh.json
@@ -577,5 +577,21 @@
"MenuLink": "菜单",
"Placeholder": "名称",
"Start": "开始"
+ },
+ "reportBug": {
+ "Title": "Unhandled error",
+ "SubTitle": "Would you like to submit a bug report?",
+ "TechnicalDetails": "Technical details",
+ "Description": "We have encountered an error while loading this page. Be a fellow superhero and help us improve our service by sending us a bug report. Only technical details and no personal data will be submitted.",
+ "DescriptionTitle": "Bug description",
+ "Send": "Submit",
+ "Cancel": "Cancel",
+ "Placeholder": "Describe the bug you encountered (optional)",
+ "Success": {
+ "Title": "Thank you!",
+ "SubTitle": "Your bug report has been submitted.",
+ "Description": "Thank you for being such a wonderful fellow superhero. The information provided will help us to improve our product and services for the benefit of the whole Superhero community.",
+ "Return": "Return to website"
+ }
}
}
diff --git a/src/store/index.js b/src/store/index.js
index 9103b84ee..e62a65a4d 100644
--- a/src/store/index.js
+++ b/src/store/index.js
@@ -7,6 +7,7 @@ import { camelCase } from 'lodash-es';
import mutations from './mutations';
import getters from './getters';
import modals from './plugins/modals';
+import errorHandler from './plugins/errorHandler';
import backend from './modules/backend';
import aeternity from './modules/aeternity';
import Backend from '../utils/backend';
@@ -124,5 +125,6 @@ export default () => new Vuex.Store({
},
plugins: [
modals,
+ errorHandler,
],
});
diff --git a/src/store/plugins/errorHandler.js b/src/store/plugins/errorHandler.js
new file mode 100644
index 000000000..4203012a7
--- /dev/null
+++ b/src/store/plugins/errorHandler.js
@@ -0,0 +1,54 @@
+import { serializeError } from 'serialize-error';
+import Vue from 'vue';
+
+export default ({ dispatch }) => {
+ const reportsToSend = [];
+ let showingErrorReportModal = false;
+
+ const handleError = async (error) => {
+ reportsToSend.push({
+ appName: 'superhero-ui',
+ appVersion: process.env.npm_package_version,
+ appRevision: process.env.COMMIT_HASH,
+ userAgent: window.navigator.userAgent,
+ location: window.location.href,
+ timestamp: Date.now(),
+ error,
+ });
+ if (showingErrorReportModal) return;
+ showingErrorReportModal = true;
+ let isReportSubmitted = false;
+ while (reportsToSend.length) {
+ // eslint-disable-next-line no-await-in-loop
+ isReportSubmitted = await dispatch('modals/open', {
+ name: 'error-report-modal',
+ report: reportsToSend.shift(),
+ }) || isReportSubmitted;
+ }
+ if (isReportSubmitted) {
+ await dispatch('modals/open', { name: 'error-report-submitted-modal' });
+ }
+ showingErrorReportModal = false;
+ };
+
+ window.addEventListener('unhandledrejection', (event) => handleError({
+ exceptionType: 'unhandled-rejection',
+ ...serializeError(event.reason),
+ }));
+ window.onerror = (message, source, line, col, error) => handleError({
+ exceptionType: 'unhandled-error',
+ message,
+ source,
+ line,
+ col,
+ ...serializeError(error),
+ });
+ Vue.config.errorHandler = async (error, vm, info) => {
+ console.error(error);
+ await handleError({
+ exceptionType: 'unhandled-vue-error',
+ info,
+ ...serializeError(error),
+ });
+ };
+};
diff --git a/src/utils/backend.js b/src/utils/backend.js
index 192ef55f5..a57087b97 100644
--- a/src/utils/backend.js
+++ b/src/utils/backend.js
@@ -160,4 +160,12 @@ export default class Backend {
body: JSON.stringify(postParam),
headers: { 'Content-Type': 'application/json' },
});
+
+ static errorReport = (report) => {
+ backendFetch('errorreport', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify(report),
+ });
+ };
}
diff --git a/src/views/modals.js b/src/views/modals.js
index 384635c0c..ebd531533 100644
--- a/src/views/modals.js
+++ b/src/views/modals.js
@@ -7,6 +7,8 @@ import FeedItemMenu from '../components/FeedItemMenu.vue';
import TokenSelect from '../components/TokenSelect.vue';
import TipInputPopup from '../components/TipInputPopup.vue';
import CookiesDialog from '../components/CookiesDialog.vue';
+import ErrorReportModal from '../components/ErrorReportModal.vue';
+import ErrorReportSubmittedModal from '../components/ErrorReportSubmittedModal.vue';
export default () => {
registerModal({ name: 'success', component: AlertModal, allowRedirect: true });
@@ -48,4 +50,14 @@ export default () => {
component: CookiesDialog,
resolveNullOnRedirect: true,
});
+ registerModal({
+ name: 'error-report-modal',
+ component: ErrorReportModal,
+ allowRedirect: true,
+ });
+ registerModal({
+ name: 'error-report-submitted-modal',
+ component: ErrorReportSubmittedModal,
+ allowRedirect: true,
+ });
};
From a382910dff8a833b4428f90d88ee78abaa9c7b66 Mon Sep 17 00:00:00 2001
From: Denis Davidyuk
Date: Wed, 14 Jul 2021 05:18:45 +0300
Subject: [PATCH 5/6] fix: handle exceptions of callWithAuth
---
src/App.vue | 6 +++++-
src/components/CookiesDialog.vue | 8 ++++++--
src/components/UserInfo.vue | 12 +++++++++++-
src/store/index.js | 7 +++++--
src/store/modules/backend.js | 3 +--
5 files changed, 28 insertions(+), 8 deletions(-)
diff --git a/src/App.vue b/src/App.vue
index 52606a6a2..0790936a3 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -101,7 +101,11 @@ export default {
console.log('found wallet');
this.useSdkWallet();
this.setAddress(address);
- this.$store.dispatch('updateCookiesConsent');
+ try {
+ await this.$store.dispatch('updateCookiesConsent');
+ } catch (error) {
+ if (error.message !== 'Operation rejected by user') throw error;
+ }
} else {
this.setAddress(address);
}
diff --git a/src/components/CookiesDialog.vue b/src/components/CookiesDialog.vue
index 46816fd4b..7fef77ae6 100644
--- a/src/components/CookiesDialog.vue
+++ b/src/components/CookiesDialog.vue
@@ -71,8 +71,12 @@ export default {
},
methods: {
async allowHandler() {
- await this.$store.dispatch('backend/setCookies', { scope: this.scope, status: true });
- this.resolve();
+ try {
+ await this.$store.dispatch('backend/setCookies', { scope: this.scope, status: true });
+ this.resolve();
+ } catch (error) {
+ if (error.message !== 'Operation rejected by user') throw error;
+ }
},
},
};
diff --git a/src/components/UserInfo.vue b/src/components/UserInfo.vue
index ed9bab1e6..b9088ca92 100644
--- a/src/components/UserInfo.vue
+++ b/src/components/UserInfo.vue
@@ -175,7 +175,7 @@
:key="scope"
class="cookies-button"
:class="{ active: cookiesConsent[scope] }"
- @click="setCookies({ scope, status: !cookiesConsent[scope] })"
+ @click="toggleCookiesConsent(scope)"
>
{{ scope }}
@@ -382,6 +382,16 @@ export default {
this.profile.biography = this.profile.biography || '';
if (this.isOwn) this.$store.commit('setUserProfile', this.profile);
},
+ async toggleCookiesConsent(scope) {
+ try {
+ await this.$store.dispatch(
+ 'backend/setCookies',
+ { scope, status: !this.cookiesConsent[scope] },
+ );
+ } catch (error) {
+ if (error.message !== 'Operation rejected by user') throw error;
+ }
+ },
},
};
diff --git a/src/store/index.js b/src/store/index.js
index e62a65a4d..d95d1efce 100644
--- a/src/store/index.js
+++ b/src/store/index.js
@@ -43,8 +43,11 @@ export default () => new Vuex.Store({
commit('setPinnedItems', await Backend.getPinnedItems(address));
},
async updateCookiesConsent({ commit, dispatch }) {
- dispatch('backend/callWithAuth', { method: 'getCookiesConsent' })
- .then((list) => list.forEach(({ scope, status }) => commit('setCookiesConsent', { scope, status: status === 'ALLOWED' })));
+ const list = await dispatch('backend/callWithAuth', { method: 'getCookiesConsent' });
+ list.forEach(({ scope, status }) => commit('setCookiesConsent', {
+ scope,
+ status: status === 'ALLOWED',
+ }));
},
async getTokenBalance({ state: { address, middleware } }, contractAddress) {
const result = await middleware.getAex9Balance(contractAddress, address);
diff --git a/src/store/modules/backend.js b/src/store/modules/backend.js
index 54b3062fb..846dcc53a 100644
--- a/src/store/modules/backend.js
+++ b/src/store/modules/backend.js
@@ -130,8 +130,7 @@ export default {
const { challenge } = await Backend[method](address, arg);
if (useSdkWallet) {
const signature = await sdk.signMessage(challenge);
- const response = await Backend[method](address, { challenge, signature });
- return response;
+ return Backend[method](address, { challenge, signature });
}
const url = new URL(to || window.location, window.location);
From e06974252077c879930173fa5b4062a0e01b7c5f Mon Sep 17 00:00:00 2001
From: Nikita Cedrik
Date: Fri, 10 Sep 2021 12:34:03 +1000
Subject: [PATCH 6/6] fix(error-handler): form a correct report
---
package-lock.json | 5 +++++
package.json | 1 +
src/components/ErrorReportModal.vue | 2 +-
src/store/plugins/errorHandler.js | 15 +++++++++------
4 files changed, 16 insertions(+), 7 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 2bf11ed21..3dc2d1c32 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8705,6 +8705,11 @@
"resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz",
"integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0="
},
+ "detect-browser": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/detect-browser/-/detect-browser-5.2.0.tgz",
+ "integrity": "sha512-tr7XntDAu50BVENgQfajMLzacmSe34D+qZc4zjnniz0ZVuw/TZcLcyxHQjYpJTM36sGEkZZlYLnIM1hH7alTMA=="
+ },
"dns-packet": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.4.tgz",
diff --git a/package.json b/package.json
index 5fdc0a8cb..c21f26839 100644
--- a/package.json
+++ b/package.json
@@ -40,6 +40,7 @@
"connect": "^3.7.0",
"core-js": "^3.15.1",
"date-fns": "^2.22.1",
+ "detect-browser": "^5.2.0",
"fontsource-ibm-plex-sans": "^3.1.5",
"i18n": "^0.13.3",
"is-fqdn": "^2.0.1",
diff --git a/src/components/ErrorReportModal.vue b/src/components/ErrorReportModal.vue
index c1a206afa..08248b4b4 100644
--- a/src/components/ErrorReportModal.vue
+++ b/src/components/ErrorReportModal.vue
@@ -67,7 +67,7 @@ export default {
async send() {
await Backend.errorReport({
...this.report,
- userComment: this.userComment,
+ description: this.userComment,
});
this.resolve(true);
},
diff --git a/src/store/plugins/errorHandler.js b/src/store/plugins/errorHandler.js
index 4203012a7..ea3712603 100644
--- a/src/store/plugins/errorHandler.js
+++ b/src/store/plugins/errorHandler.js
@@ -1,5 +1,6 @@
import { serializeError } from 'serialize-error';
import Vue from 'vue';
+import { detect } from 'detect-browser';
export default ({ dispatch }) => {
const reportsToSend = [];
@@ -7,13 +8,15 @@ export default ({ dispatch }) => {
const handleError = async (error) => {
reportsToSend.push({
- appName: 'superhero-ui',
appVersion: process.env.npm_package_version,
- appRevision: process.env.COMMIT_HASH,
- userAgent: window.navigator.userAgent,
- location: window.location.href,
- timestamp: Date.now(),
- error,
+ browser: detect(),
+ platform: 'superhero-ui',
+ time: Date.now(),
+ error: {
+ ...error,
+ appRevision: process.env.COMMIT_HASH,
+ location: window.location.href,
+ },
});
if (showingErrorReportModal) return;
showingErrorReportModal = true;