From 4670e1061ba33282444c3831ffa0ef00e7e5cc74 Mon Sep 17 00:00:00 2001 From: Alexandros Kalogerakis Date: Mon, 4 Nov 2024 11:54:38 +0200 Subject: [PATCH] feat: export error log and show error modals on transaction errors --- src/composables/addressBook.ts | 28 +--- src/constants/common.ts | 1 + src/lib/logger.ts | 39 ++++- .../AddressBook/AddressBookList.vue | 1 + src/popup/components/InputField.vue | 2 +- .../Modals/ConfirmDisableErrorLog.vue | 148 ++++++++++++++++++ src/popup/components/Modals/Default.vue | 38 ++++- .../components/Modals/MultisigVaultCreate.vue | 15 +- src/popup/components/buttons/BtnSubheader.vue | 2 +- src/popup/locales/en.json | 13 +- src/popup/pages/ErrorLogSettings.vue | 50 +++++- src/popup/pages/SignTransaction.vue | 16 +- src/popup/router/modals.ts | 90 ++++++----- .../aeternity/components/TransferReview.vue | 37 ++--- .../components/TransferSignedTxReview.vue | 9 +- .../aeternity/libs/AeAccountHdWallet.ts | 11 +- .../bitcoin/components/TransferReview.vue | 17 +- .../ethereum/components/TransferReview.vue | 14 +- src/utils/common.ts | 26 +++ 19 files changed, 415 insertions(+), 142 deletions(-) create mode 100644 src/popup/components/Modals/ConfirmDisableErrorLog.vue diff --git a/src/composables/addressBook.ts b/src/composables/addressBook.ts index addbd5df7..89aed0e28 100644 --- a/src/composables/addressBook.ts +++ b/src/composables/addressBook.ts @@ -1,6 +1,4 @@ import { computed, ref, watch } from 'vue'; -import { Directory, Filesystem } from '@capacitor/filesystem'; -import { Capacitor } from '@capacitor/core'; import { AccountAddress, @@ -10,12 +8,12 @@ import { import { STORAGE_KEYS, MODAL_ADDRESS_BOOK_IMPORT } from '@/constants'; import { AddressBookEntryExists, AddressBookInvalidAddress, AddressBookRequiredFields } from '@/lib/errors'; import { - convertBlobToBase64, createCustomScopedComposable, getProtocolByAddress, handleUnknownError, selectFiles, pipe, + exportFile, } from '@/utils'; import { tg as t } from '@/popup/plugins/i18n'; @@ -170,29 +168,15 @@ export const useAddressBook = createCustomScopedComposable(() => { } async function exportAddressBook() { - const json = JSON.stringify(addressBook.value); - const blob = new Blob([json], { type: 'text/plain' }); - const a = document.createElement('a'); - const href = window.URL.createObjectURL(blob); - const filename = 'addressBookExport.json'; - - if (Capacitor.isNativePlatform()) { - const base64 = await convertBlobToBase64(blob); - const saveFile = await Filesystem.writeFile({ - path: filename, - data: base64, - directory: Directory.Documents, - }); - const path = saveFile.uri; + const path = await exportFile( + JSON.stringify(addressBook.value), + 'addressBookExport.json', + ); + if (path) { openDefaultModal({ title: t('pages.addressBook.export.title'), msg: t('pages.addressBook.export.message') + path, }); - } else { - a.download = filename; - a.href = href; - a.dataset.downloadurl = ['text/json', a.download, a.href].join(':'); - a.click(); } } diff --git a/src/constants/common.ts b/src/constants/common.ts index a1dd9c332..17703e000 100644 --- a/src/constants/common.ts +++ b/src/constants/common.ts @@ -326,6 +326,7 @@ export const MODAL_CONFIRM_RAW_SIGN = 'confirm-raw-sign'; export const MODAL_CONFIRM_UNSAFE_SIGN = 'confirm-unsafe-sign'; export const MODAL_CONFIRM_CONNECT = 'confirm-connect'; export const MODAL_CONFIRM_ACCOUNT_LIST = 'confirm-account-list'; +export const MODAL_CONFIRM_DISABLE_ERROR_LOG = 'confirm-disable-error-log'; export const MODAL_CONSENSUS_INFO = 'consensus-info'; export const MODAL_DEFAULT = 'default'; export const MODAL_ERROR_LOG = 'error-log'; diff --git a/src/lib/logger.ts b/src/lib/logger.ts index 199ec9af6..4cb4b2589 100644 --- a/src/lib/logger.ts +++ b/src/lib/logger.ts @@ -2,10 +2,14 @@ import { pick } from 'lodash-es'; import { detect } from 'detect-browser'; import { App, ComputedRef } from 'vue'; + import { IS_PRODUCTION, STORAGE_KEYS } from '@/constants'; -import { useModals, useUi } from '../composables'; -import { RejectedByUserError } from './errors'; +import { exportFile } from '@/utils'; +import { tg as t } from '@/popup/plugins/i18n'; +import { useModals, useUi } from '@/composables'; + import { WalletStorage } from './WalletStorage'; +import { RejectedByUserError } from './errors'; interface ILoggerOptions { background?: boolean; @@ -21,6 +25,7 @@ interface ILoggerEntry { } interface ILoggerInput { + title?: string; modal?: boolean; message: string; type: 'vue-error' | 'unhandledrejection' | 'window-error' | 'api-response'; @@ -87,6 +92,15 @@ export default class Logger { } static write({ modal = !IS_PRODUCTION, ...error }: ILoggerInput) { + if (!Logger.background && modal && error.message) { + const { openDefaultModal } = useModals(); + openDefaultModal({ + icon: 'critical', + title: error.title || t('modals.error-log.title'), + msg: error.message, + textCenter: true, + }); + } if (!Logger.saveErrorLog.value) { return; } @@ -99,10 +113,6 @@ export default class Logger { time: Date.now(), }; WalletStorage.set(STORAGE_KEYS.errorLog, [...errorLog, logEntry]); - if (!Logger.background && modal && error.message) { - const { openErrorModal } = useModals(); - openErrorModal(logEntry); - } } static get(): ILoggerEntry[] { @@ -115,4 +125,21 @@ export default class Logger { // TODO: make call to backend here } } + + static async exportErrorLog(clear: boolean = false) { + const path = await exportFile( + JSON.stringify(Logger.get()), + 'errorLogExport.json', + ); + if (path) { + const { openDefaultModal } = useModals(); + openDefaultModal({ + title: t('pages.addressBook.export.title'), + msg: t('pages.addressBook.export.message') + path, + }); + } + if (clear) { + WalletStorage.set(STORAGE_KEYS.errorLog, []); + } + } } diff --git a/src/popup/components/AddressBook/AddressBookList.vue b/src/popup/components/AddressBook/AddressBookList.vue index 1ebdcbfee..eecd9e263 100644 --- a/src/popup/components/AddressBook/AddressBookList.vue +++ b/src/popup/components/AddressBook/AddressBookList.vue @@ -253,6 +253,7 @@ export default defineComponent({ .address-book-item { background-color: var(--bg-color); border: var(--border-width) solid var(--bg-color); + padding: 8px 2px 8px 8px; } .search-field { diff --git a/src/popup/components/InputField.vue b/src/popup/components/InputField.vue index 76905118d..2e52b9a91 100644 --- a/src/popup/components/InputField.vue +++ b/src/popup/components/InputField.vue @@ -355,7 +355,7 @@ export default defineComponent({ .input-wrapper { position: relative; display: block; - padding: 10px 8px 12px 10px; // Decides on the input size + padding: 10px 8px 10px 10px; // Decides on the input size background-color: var(--color-bg); border: none; border-radius: $border-radius-interactive; diff --git a/src/popup/components/Modals/ConfirmDisableErrorLog.vue b/src/popup/components/Modals/ConfirmDisableErrorLog.vue new file mode 100644 index 000000000..e796c3776 --- /dev/null +++ b/src/popup/components/Modals/ConfirmDisableErrorLog.vue @@ -0,0 +1,148 @@ + + + + + diff --git a/src/popup/components/Modals/Default.vue b/src/popup/components/Modals/Default.vue index 3901adb9e..ab88206ac 100644 --- a/src/popup/components/Modals/Default.vue +++ b/src/popup/components/Modals/Default.vue @@ -37,6 +37,14 @@