|  |  | @ -82,6 +82,7 @@ | 
			
		
	
		
			
				
					|  |  |  |     <router-link | 
			
		
	
		
			
				
					|  |  |  |       :to="{ name: 'new-edit-account' }" | 
			
		
	
		
			
				
					|  |  |  |       class="block text-center text-lg font-bold uppercase bg-slate-500 text-white px-2 py-3 rounded-md mb-2" | 
			
		
	
		
			
				
					|  |  |  |       v-if="activeDid" | 
			
		
	
		
			
				
					|  |  |  |     > | 
			
		
	
		
			
				
					|  |  |  |       Edit Identity | 
			
		
	
		
			
				
					|  |  |  |     </router-link> | 
			
		
	
	
		
			
				
					|  |  | @ -153,7 +154,7 @@ | 
			
		
	
		
			
				
					|  |  |  |       </label> | 
			
		
	
		
			
				
					|  |  |  |     </div> | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     <h3 class="text-sm uppercase font-semibold mb-3">Data</h3> | 
			
		
	
		
			
				
					|  |  |  |     <h3 class="text-sm uppercase font-semibold mb-3">Data Export</h3> | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     <router-link | 
			
		
	
		
			
				
					|  |  |  |       :to="{ name: 'seed-backup' }" | 
			
		
	
	
		
			
				
					|  |  | @ -180,7 +181,7 @@ | 
			
		
	
		
			
				
					|  |  |  |       If no download happened yet, click again here to download now. | 
			
		
	
		
			
				
					|  |  |  |     </a> | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     <div v-if="activeDid" class="flex py-2"> | 
			
		
	
		
			
				
					|  |  |  |     <div v-if="activeDid" class="flex mt-8 py-2"> | 
			
		
	
		
			
				
					|  |  |  |       <button class="text-center text-md text-blue-500" @click="checkLimits()"> | 
			
		
	
		
			
				
					|  |  |  |         Check Limits | 
			
		
	
		
			
				
					|  |  |  |       </button> | 
			
		
	
	
		
			
				
					|  |  | @ -306,6 +307,21 @@ | 
			
		
	
		
			
				
					|  |  |  |         </div> | 
			
		
	
		
			
				
					|  |  |  |       </label> | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |       <div class="grid-cols-2"> | 
			
		
	
		
			
				
					|  |  |  |         <span class="text-slate-500 text-sm font-bold mb-2">Data Import</span> | 
			
		
	
		
			
				
					|  |  |  |         <input type="file" @change="uploadFile" class="ml-2" /> | 
			
		
	
		
			
				
					|  |  |  |         <div v-if="showContactImport()"> | 
			
		
	
		
			
				
					|  |  |  |           <button | 
			
		
	
		
			
				
					|  |  |  |             class="block text-center text-md uppercase bg-slate-500 text-white px-1.5 py-2 rounded-md mb-6" | 
			
		
	
		
			
				
					|  |  |  |             @click="submitFile()" | 
			
		
	
		
			
				
					|  |  |  |           > | 
			
		
	
		
			
				
					|  |  |  |             Import Settings & Contacts | 
			
		
	
		
			
				
					|  |  |  |             <br /> | 
			
		
	
		
			
				
					|  |  |  |             (excluding Identifier Data) | 
			
		
	
		
			
				
					|  |  |  |           </button> | 
			
		
	
		
			
				
					|  |  |  |         </div> | 
			
		
	
		
			
				
					|  |  |  |       </div> | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |       <div class="flex py-2"> | 
			
		
	
		
			
				
					|  |  |  |         <button class="text-blue-500"> | 
			
		
	
		
			
				
					|  |  |  |           <router-link :to="{ name: 'statistics' }" class="block text-center"> | 
			
		
	
	
		
			
				
					|  |  | @ -407,7 +423,9 @@ | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | <script lang="ts"> | 
			
		
	
		
			
				
					|  |  |  | import { AxiosError, AxiosRequestConfig } from "axios"; | 
			
		
	
		
			
				
					|  |  |  | import Dexie from "dexie"; | 
			
		
	
		
			
				
					|  |  |  | import "dexie-export-import"; | 
			
		
	
		
			
				
					|  |  |  | import { ref } from "vue"; | 
			
		
	
		
			
				
					|  |  |  | import { Component, Vue } from "vue-facing-decorator"; | 
			
		
	
		
			
				
					|  |  |  | import { useClipboard } from "@vueuse/core"; | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
	
		
			
				
					|  |  | @ -418,6 +436,7 @@ import { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings"; | 
			
		
	
		
			
				
					|  |  |  | import { accessToken } from "@/libs/crypto"; | 
			
		
	
		
			
				
					|  |  |  | import { IIdentifier } from "@veramo/core"; | 
			
		
	
		
			
				
					|  |  |  | import { ErrorResponse, RateLimits } from "@/libs/endorserServer"; | 
			
		
	
		
			
				
					|  |  |  | import { ImportProgress } from "dexie-export-import/dist/import"; | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | // eslint-disable-next-line @typescript-eslint/no-var-requires | 
			
		
	
		
			
				
					|  |  |  | const Buffer = require("buffer/").Buffer; | 
			
		
	
	
		
			
				
					|  |  | @ -436,6 +455,8 @@ interface IAccount { | 
			
		
	
		
			
				
					|  |  |  |   derivationPath: string; | 
			
		
	
		
			
				
					|  |  |  | } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | const inputFileNameRef = ref<Blob>(); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | @Component({ components: { QuickNav } }) | 
			
		
	
		
			
				
					|  |  |  | export default class AccountViewView extends Vue { | 
			
		
	
		
			
				
					|  |  |  |   $notify!: (notification: Notification, timeout?: number) => void; | 
			
		
	
	
		
			
				
					|  |  | @ -480,26 +501,18 @@ export default class AccountViewView extends Vue { | 
			
		
	
		
			
				
					|  |  |  |     try { | 
			
		
	
		
			
				
					|  |  |  |       // Open the accounts database | 
			
		
	
		
			
				
					|  |  |  |       await accountsDB.open(); | 
			
		
	
		
			
				
					|  |  |  |     } catch (error) { | 
			
		
	
		
			
				
					|  |  |  |       console.error("Failed to open accounts database:", error); | 
			
		
	
		
			
				
					|  |  |  |       return null; | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     let account: { identity?: string } | undefined; | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     try { | 
			
		
	
		
			
				
					|  |  |  |       // Search for the account with the matching DID (decentralized identifier) | 
			
		
	
		
			
				
					|  |  |  |       account = await accountsDB.accounts | 
			
		
	
		
			
				
					|  |  |  |         .where("did") | 
			
		
	
		
			
				
					|  |  |  |         .equals(activeDid) | 
			
		
	
		
			
				
					|  |  |  |         .first(); | 
			
		
	
		
			
				
					|  |  |  |       const account: { identity?: string } | undefined = | 
			
		
	
		
			
				
					|  |  |  |         await accountsDB.accounts.where("did").equals(activeDid).first(); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |       accountsDB.close(); | 
			
		
	
		
			
				
					|  |  |  |       // Return parsed identity or null if not found | 
			
		
	
		
			
				
					|  |  |  |       return JSON.parse((account?.identity as string) || "null"); | 
			
		
	
		
			
				
					|  |  |  |     } catch (error) { | 
			
		
	
		
			
				
					|  |  |  |       console.error("Failed to find account:", error); | 
			
		
	
		
			
				
					|  |  |  |       return null; | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     // Return parsed identity or null if not found | 
			
		
	
		
			
				
					|  |  |  |     return JSON.parse((account?.identity as string) || "null"); | 
			
		
	
		
			
				
					|  |  |  |   } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |   /** | 
			
		
	
	
		
			
				
					|  |  | @ -548,6 +561,7 @@ export default class AccountViewView extends Vue { | 
			
		
	
		
			
				
					|  |  |  |   async beforeCreate() { | 
			
		
	
		
			
				
					|  |  |  |     await accountsDB.open(); | 
			
		
	
		
			
				
					|  |  |  |     this.numAccounts = await accountsDB.accounts.count(); | 
			
		
	
		
			
				
					|  |  |  |     accountsDB.close(); | 
			
		
	
		
			
				
					|  |  |  |   } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |   /** | 
			
		
	
	
		
			
				
					|  |  | @ -572,6 +586,7 @@ export default class AccountViewView extends Vue { | 
			
		
	
		
			
				
					|  |  |  |       if (identity) { | 
			
		
	
		
			
				
					|  |  |  |         this.processIdentity(identity); | 
			
		
	
		
			
				
					|  |  |  |       } | 
			
		
	
		
			
				
					|  |  |  |       db.close(); | 
			
		
	
		
			
				
					|  |  |  |     } catch (err: unknown) { | 
			
		
	
		
			
				
					|  |  |  |       this.handleError(err); | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
	
		
			
				
					|  |  | @ -668,6 +683,7 @@ export default class AccountViewView extends Vue { | 
			
		
	
		
			
				
					|  |  |  |       db.settings.update(MASTER_SETTINGS_KEY, { | 
			
		
	
		
			
				
					|  |  |  |         showContactGivesInline: this.showContactGives, | 
			
		
	
		
			
				
					|  |  |  |       }); | 
			
		
	
		
			
				
					|  |  |  |       db.close(); | 
			
		
	
		
			
				
					|  |  |  |     } catch (err) { | 
			
		
	
		
			
				
					|  |  |  |       this.$notify( | 
			
		
	
		
			
				
					|  |  |  |         { | 
			
		
	
	
		
			
				
					|  |  | @ -787,6 +803,43 @@ export default class AccountViewView extends Vue { | 
			
		
	
		
			
				
					|  |  |  |     console.error("Export Error:", error); | 
			
		
	
		
			
				
					|  |  |  |   } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |   // eslint-disable-next-line @typescript-eslint/no-explicit-any | 
			
		
	
		
			
				
					|  |  |  |   async uploadFile(event: any) { | 
			
		
	
		
			
				
					|  |  |  |     inputFileNameRef.value = event.target.files[0]; | 
			
		
	
		
			
				
					|  |  |  |   } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |   showContactImport() { | 
			
		
	
		
			
				
					|  |  |  |     return !!inputFileNameRef.value; | 
			
		
	
		
			
				
					|  |  |  |   } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |   /** | 
			
		
	
		
			
				
					|  |  |  |    * Asynchronously imports the database from a downloadable JSON file. | 
			
		
	
		
			
				
					|  |  |  |    * | 
			
		
	
		
			
				
					|  |  |  |    * @throws Will notify the user if there is an export error. | 
			
		
	
		
			
				
					|  |  |  |    */ | 
			
		
	
		
			
				
					|  |  |  |   async submitFile() { | 
			
		
	
		
			
				
					|  |  |  |     if (inputFileNameRef.value != null) { | 
			
		
	
		
			
				
					|  |  |  |       if ( | 
			
		
	
		
			
				
					|  |  |  |         confirm( | 
			
		
	
		
			
				
					|  |  |  |           "This will replace all settings and contacts, so we recommend you first do the backup step above." + | 
			
		
	
		
			
				
					|  |  |  |             " Are you sure you want to import and replace all contacts and settings?", | 
			
		
	
		
			
				
					|  |  |  |         ) | 
			
		
	
		
			
				
					|  |  |  |       ) { | 
			
		
	
		
			
				
					|  |  |  |         await db.delete(); | 
			
		
	
		
			
				
					|  |  |  |         await Dexie.import(inputFileNameRef.value, { | 
			
		
	
		
			
				
					|  |  |  |           progressCallback: this.progressCallback, | 
			
		
	
		
			
				
					|  |  |  |         }); | 
			
		
	
		
			
				
					|  |  |  |       } | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |   } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |   private progressCallback(progress: ImportProgress) { | 
			
		
	
		
			
				
					|  |  |  |     console.log( | 
			
		
	
		
			
				
					|  |  |  |       `Import progress: ${progress.completedRows} of ${progress.totalRows} rows completed.`, | 
			
		
	
		
			
				
					|  |  |  |     ); | 
			
		
	
		
			
				
					|  |  |  |     return true; | 
			
		
	
		
			
				
					|  |  |  |   } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |   async checkLimits() { | 
			
		
	
		
			
				
					|  |  |  |     const identity = await this.getIdentity(this.activeDid); | 
			
		
	
		
			
				
					|  |  |  |     if (identity) { | 
			
		
	
	
		
			
				
					|  |  | @ -815,6 +868,7 @@ export default class AccountViewView extends Vue { | 
			
		
	
		
			
				
					|  |  |  |               isRegistered: true, | 
			
		
	
		
			
				
					|  |  |  |             }); | 
			
		
	
		
			
				
					|  |  |  |             this.isRegistered = true; | 
			
		
	
		
			
				
					|  |  |  |             db.close(); | 
			
		
	
		
			
				
					|  |  |  |           } catch (err) { | 
			
		
	
		
			
				
					|  |  |  |             console.error("Got an error updating settings:", err); | 
			
		
	
		
			
				
					|  |  |  |             this.$notify( | 
			
		
	
	
		
			
				
					|  |  | @ -886,6 +940,7 @@ export default class AccountViewView extends Vue { | 
			
		
	
		
			
				
					|  |  |  |     } else { | 
			
		
	
		
			
				
					|  |  |  |       await this.switchToAccountNumber(accountNum); | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |     db.close(); | 
			
		
	
		
			
				
					|  |  |  |   } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |   /** | 
			
		
	
	
		
			
				
					|  |  | @ -916,9 +971,12 @@ export default class AccountViewView extends Vue { | 
			
		
	
		
			
				
					|  |  |  |     const accounts = await accountsDB.accounts.toArray(); | 
			
		
	
		
			
				
					|  |  |  |     const account = accounts[accountNum - 1]; | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     await db.open(); | 
			
		
	
		
			
				
					|  |  |  |     await db.settings.update(MASTER_SETTINGS_KEY, { activeDid: account.did }); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     this.updateActiveAccountProperties(account); | 
			
		
	
		
			
				
					|  |  |  |     db.close(); | 
			
		
	
		
			
				
					|  |  |  |     accountsDB.close(); | 
			
		
	
		
			
				
					|  |  |  |   } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |   /** | 
			
		
	
	
		
			
				
					|  |  | @ -946,6 +1004,7 @@ export default class AccountViewView extends Vue { | 
			
		
	
		
			
				
					|  |  |  |       apiServer: this.apiServerInput, | 
			
		
	
		
			
				
					|  |  |  |     }); | 
			
		
	
		
			
				
					|  |  |  |     this.apiServer = this.apiServerInput; | 
			
		
	
		
			
				
					|  |  |  |     db.close(); | 
			
		
	
		
			
				
					|  |  |  |   } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |   async onClickSavePushServer() { | 
			
		
	
	
		
			
				
					|  |  | @ -963,6 +1022,7 @@ export default class AccountViewView extends Vue { | 
			
		
	
		
			
				
					|  |  |  |       }, | 
			
		
	
		
			
				
					|  |  |  |       -1, | 
			
		
	
		
			
				
					|  |  |  |     ); | 
			
		
	
		
			
				
					|  |  |  |     db.close(); | 
			
		
	
		
			
				
					|  |  |  |   } | 
			
		
	
		
			
				
					|  |  |  | } | 
			
		
	
		
			
				
					|  |  |  | </script> | 
			
		
	
	
		
			
				
					|  |  | 
 |