Browse Source

add a way to import contacts & settings

starred-projects
Trent Larson 11 months ago
parent
commit
c79dfac1fe
  1. 92
      src/views/AccountViewView.vue

92
src/views/AccountViewView.vue

@ -82,6 +82,7 @@
<router-link <router-link
:to="{ name: 'new-edit-account' }" :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" 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 Edit Identity
</router-link> </router-link>
@ -153,7 +154,7 @@
</label> </label>
</div> </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 <router-link
:to="{ name: 'seed-backup' }" :to="{ name: 'seed-backup' }"
@ -180,7 +181,7 @@
If no download happened yet, click again here to download now. If no download happened yet, click again here to download now.
</a> </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()"> <button class="text-center text-md text-blue-500" @click="checkLimits()">
Check Limits Check Limits
</button> </button>
@ -306,6 +307,21 @@
</div> </div>
</label> </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"> <div class="flex py-2">
<button class="text-blue-500"> <button class="text-blue-500">
<router-link :to="{ name: 'statistics' }" class="block text-center"> <router-link :to="{ name: 'statistics' }" class="block text-center">
@ -407,7 +423,9 @@
<script lang="ts"> <script lang="ts">
import { AxiosError, AxiosRequestConfig } from "axios"; import { AxiosError, AxiosRequestConfig } from "axios";
import Dexie from "dexie";
import "dexie-export-import"; import "dexie-export-import";
import { ref } from "vue";
import { Component, Vue } from "vue-facing-decorator"; import { Component, Vue } from "vue-facing-decorator";
import { useClipboard } from "@vueuse/core"; import { useClipboard } from "@vueuse/core";
@ -418,6 +436,7 @@ import { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings";
import { accessToken } from "@/libs/crypto"; import { accessToken } from "@/libs/crypto";
import { IIdentifier } from "@veramo/core"; import { IIdentifier } from "@veramo/core";
import { ErrorResponse, RateLimits } from "@/libs/endorserServer"; import { ErrorResponse, RateLimits } from "@/libs/endorserServer";
import { ImportProgress } from "dexie-export-import/dist/import";
// eslint-disable-next-line @typescript-eslint/no-var-requires // eslint-disable-next-line @typescript-eslint/no-var-requires
const Buffer = require("buffer/").Buffer; const Buffer = require("buffer/").Buffer;
@ -436,6 +455,8 @@ interface IAccount {
derivationPath: string; derivationPath: string;
} }
const inputFileNameRef = ref<Blob>();
@Component({ components: { QuickNav } }) @Component({ components: { QuickNav } })
export default class AccountViewView extends Vue { export default class AccountViewView extends Vue {
$notify!: (notification: Notification, timeout?: number) => void; $notify!: (notification: Notification, timeout?: number) => void;
@ -480,26 +501,18 @@ export default class AccountViewView extends Vue {
try { try {
// Open the accounts database // Open the accounts database
await accountsDB.open(); 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) // Search for the account with the matching DID (decentralized identifier)
account = await accountsDB.accounts const account: { identity?: string } | undefined =
.where("did") await accountsDB.accounts.where("did").equals(activeDid).first();
.equals(activeDid)
.first(); accountsDB.close();
// Return parsed identity or null if not found
return JSON.parse((account?.identity as string) || "null");
} catch (error) { } catch (error) {
console.error("Failed to find account:", error); console.error("Failed to find account:", error);
return null; 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() { async beforeCreate() {
await accountsDB.open(); await accountsDB.open();
this.numAccounts = await accountsDB.accounts.count(); this.numAccounts = await accountsDB.accounts.count();
accountsDB.close();
} }
/** /**
@ -572,6 +586,7 @@ export default class AccountViewView extends Vue {
if (identity) { if (identity) {
this.processIdentity(identity); this.processIdentity(identity);
} }
db.close();
} catch (err: unknown) { } catch (err: unknown) {
this.handleError(err); this.handleError(err);
} }
@ -668,6 +683,7 @@ export default class AccountViewView extends Vue {
db.settings.update(MASTER_SETTINGS_KEY, { db.settings.update(MASTER_SETTINGS_KEY, {
showContactGivesInline: this.showContactGives, showContactGivesInline: this.showContactGives,
}); });
db.close();
} catch (err) { } catch (err) {
this.$notify( this.$notify(
{ {
@ -787,6 +803,43 @@ export default class AccountViewView extends Vue {
console.error("Export Error:", error); 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() { async checkLimits() {
const identity = await this.getIdentity(this.activeDid); const identity = await this.getIdentity(this.activeDid);
if (identity) { if (identity) {
@ -815,6 +868,7 @@ export default class AccountViewView extends Vue {
isRegistered: true, isRegistered: true,
}); });
this.isRegistered = true; this.isRegistered = true;
db.close();
} catch (err) { } catch (err) {
console.error("Got an error updating settings:", err); console.error("Got an error updating settings:", err);
this.$notify( this.$notify(
@ -886,6 +940,7 @@ export default class AccountViewView extends Vue {
} else { } else {
await this.switchToAccountNumber(accountNum); await this.switchToAccountNumber(accountNum);
} }
db.close();
} }
/** /**
@ -916,9 +971,12 @@ export default class AccountViewView extends Vue {
const accounts = await accountsDB.accounts.toArray(); const accounts = await accountsDB.accounts.toArray();
const account = accounts[accountNum - 1]; const account = accounts[accountNum - 1];
await db.open();
await db.settings.update(MASTER_SETTINGS_KEY, { activeDid: account.did }); await db.settings.update(MASTER_SETTINGS_KEY, { activeDid: account.did });
this.updateActiveAccountProperties(account); this.updateActiveAccountProperties(account);
db.close();
accountsDB.close();
} }
/** /**
@ -946,6 +1004,7 @@ export default class AccountViewView extends Vue {
apiServer: this.apiServerInput, apiServer: this.apiServerInput,
}); });
this.apiServer = this.apiServerInput; this.apiServer = this.apiServerInput;
db.close();
} }
async onClickSavePushServer() { async onClickSavePushServer() {
@ -963,6 +1022,7 @@ export default class AccountViewView extends Vue {
}, },
-1, -1,
); );
db.close();
} }
} }
</script> </script>

Loading…
Cancel
Save