forked from trent_larson/crowd-funder-for-time-pwa
IndexedDB migration: fix loading of data, fix object comparisons, add unmodified, etc
This commit is contained in:
@@ -19,6 +19,10 @@ export interface Contact {
|
||||
registered?: boolean; // cached value of the server setting
|
||||
}
|
||||
|
||||
export type ContactWithJsonStrings = Contact & {
|
||||
contactMethods?: string;
|
||||
}
|
||||
|
||||
export const ContactSchema = {
|
||||
contacts: "&did, name", // no need to key by other things
|
||||
};
|
||||
|
||||
@@ -64,6 +64,11 @@ export type Settings = {
|
||||
webPushServer?: string; // Web Push server URL
|
||||
};
|
||||
|
||||
// type of settings where the searchBoxes are JSON strings instead of objects
|
||||
export type SettingsWithJsonStrings = Settings & {
|
||||
searchBoxes: string;
|
||||
};
|
||||
|
||||
export function checkIsAnyFeedFilterOn(settings: Settings): boolean {
|
||||
return !!(settings?.filterFeedByNearby || settings?.filterFeedByVisible);
|
||||
}
|
||||
|
||||
@@ -26,11 +26,12 @@ import "dexie-export-import";
|
||||
import { PlatformServiceFactory } from "./PlatformServiceFactory";
|
||||
import { db, accountsDBPromise } from "../db/index";
|
||||
import { Contact, ContactMethod } from "../db/tables/contacts";
|
||||
import { Settings, MASTER_SETTINGS_KEY } from "../db/tables/settings";
|
||||
import { Account } from "../db/tables/accounts";
|
||||
import { Settings, MASTER_SETTINGS_KEY, SettingsWithJsonStrings, BoundingBox } from "../db/tables/settings";
|
||||
import { Account, AccountEncrypted } from "../db/tables/accounts";
|
||||
import { logger } from "../utils/logger";
|
||||
import { parseJsonField } from "../db/databaseUtil";
|
||||
import { mapColumnsToValues, parseJsonField } from "../db/databaseUtil";
|
||||
import { importFromMnemonic } from "../libs/util";
|
||||
import { IIdentifier } from "@veramo/core";
|
||||
|
||||
/**
|
||||
* Interface for data comparison results between Dexie and SQLite databases
|
||||
@@ -66,22 +67,24 @@ export interface DataComparison {
|
||||
dexieSettings: Settings[];
|
||||
sqliteSettings: Settings[];
|
||||
dexieAccounts: Account[];
|
||||
sqliteAccounts: Account[];
|
||||
sqliteAccounts: string[];
|
||||
differences: {
|
||||
contacts: {
|
||||
added: Contact[];
|
||||
modified: Contact[];
|
||||
unmodified: Contact[];
|
||||
missing: Contact[];
|
||||
};
|
||||
settings: {
|
||||
added: Settings[];
|
||||
modified: Settings[];
|
||||
unmodified: Settings[];
|
||||
missing: Settings[];
|
||||
};
|
||||
accounts: {
|
||||
added: Account[];
|
||||
modified: Account[];
|
||||
missing: Account[];
|
||||
unmodified: Account[];
|
||||
missing: string[];
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -184,22 +187,14 @@ export async function getSqliteContacts(): Promise<Contact[]> {
|
||||
|
||||
let contacts: Contact[] = [];
|
||||
if (result?.values?.length) {
|
||||
contacts = result.values.map((row) => {
|
||||
const contact = parseJsonField(row, {}) as Contact;
|
||||
return {
|
||||
did: contact.did || "",
|
||||
name: contact.name || "",
|
||||
contactMethods: parseJsonField(
|
||||
contact.contactMethods,
|
||||
[],
|
||||
) as ContactMethod[],
|
||||
nextPubKeyHashB64: contact.nextPubKeyHashB64 || "",
|
||||
notes: contact.notes || "",
|
||||
profileImageUrl: contact.profileImageUrl || "",
|
||||
publicKeyBase64: contact.publicKeyBase64 || "",
|
||||
seesMe: contact.seesMe || false,
|
||||
registered: contact.registered || false,
|
||||
} as Contact;
|
||||
const preContacts = mapColumnsToValues(result.columns, result.values) as unknown as Contact[];
|
||||
// This is redundant since absurd-sql auto-parses JSON strings to objects.
|
||||
// But we started it, and it should be known everywhere, so we're keeping it.
|
||||
contacts = preContacts.map((contact) => {
|
||||
if (contact.contactMethods) {
|
||||
contact.contactMethods = parseJsonField(contact.contactMethods, []) as ContactMethod[];
|
||||
}
|
||||
return contact;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -281,37 +276,16 @@ export async function getSqliteSettings(): Promise<Settings[]> {
|
||||
|
||||
let settings: Settings[] = [];
|
||||
if (result?.values?.length) {
|
||||
settings = result.values.map((row) => {
|
||||
const setting = parseJsonField(row, {}) as Settings;
|
||||
return {
|
||||
id: setting.id,
|
||||
accountDid: setting.accountDid || "",
|
||||
activeDid: setting.activeDid || "",
|
||||
apiServer: setting.apiServer || "",
|
||||
filterFeedByNearby: setting.filterFeedByNearby || false,
|
||||
filterFeedByVisible: setting.filterFeedByVisible || false,
|
||||
finishedOnboarding: setting.finishedOnboarding || false,
|
||||
firstName: setting.firstName || "",
|
||||
hideRegisterPromptOnNewContact: setting.hideRegisterPromptOnNewContact || false,
|
||||
isRegistered: setting.isRegistered || false,
|
||||
lastName: setting.lastName || "",
|
||||
lastAckedOfferToUserJwtId: setting.lastAckedOfferToUserJwtId || "",
|
||||
lastAckedOfferToUserProjectsJwtId: setting.lastAckedOfferToUserProjectsJwtId || "",
|
||||
lastNotifiedClaimId: setting.lastNotifiedClaimId || "",
|
||||
lastViewedClaimId: setting.lastViewedClaimId || "",
|
||||
notifyingNewActivityTime: setting.notifyingNewActivityTime || "",
|
||||
notifyingReminderMessage: setting.notifyingReminderMessage || "",
|
||||
notifyingReminderTime: setting.notifyingReminderTime || "",
|
||||
partnerApiServer: setting.partnerApiServer || "",
|
||||
passkeyExpirationMinutes: setting.passkeyExpirationMinutes,
|
||||
profileImageUrl: setting.profileImageUrl || "",
|
||||
searchBoxes: parseJsonField(setting.searchBoxes, []),
|
||||
showContactGivesInline: setting.showContactGivesInline || false,
|
||||
showGeneralAdvanced: setting.showGeneralAdvanced || false,
|
||||
showShortcutBvc: setting.showShortcutBvc || false,
|
||||
vapid: setting.vapid || "",
|
||||
} as Settings;
|
||||
});
|
||||
const presettings =
|
||||
mapColumnsToValues(result.columns, result.values) as Settings[];
|
||||
// This is redundant since absurd-sql auto-parses JSON strings to objects.
|
||||
// But we started it, and it should be known everywhere, so we're keeping it.
|
||||
settings = presettings.map((setting) => {
|
||||
if (setting.searchBoxes) {
|
||||
setting.searchBoxes = parseJsonField(setting.searchBoxes, []) as Array<{ name: string, bbox: BoundingBox }>;
|
||||
}
|
||||
return setting;
|
||||
})
|
||||
}
|
||||
|
||||
logger.info(
|
||||
@@ -336,7 +310,7 @@ export async function getSqliteSettings(): Promise<Settings[]> {
|
||||
*
|
||||
* @async
|
||||
* @function getSqliteAccounts
|
||||
* @returns {Promise<Account[]>} Array of all accounts from SQLite database
|
||||
* @returns {Promise<string[]>} Array of all accounts from SQLite database
|
||||
* @throws {Error} If database query fails or data conversion fails
|
||||
* @example
|
||||
* ```typescript
|
||||
@@ -348,32 +322,20 @@ export async function getSqliteSettings(): Promise<Settings[]> {
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export async function getSqliteAccounts(): Promise<Account[]> {
|
||||
export async function getSqliteAccounts(): Promise<string[]> {
|
||||
try {
|
||||
const platformService = PlatformServiceFactory.getInstance();
|
||||
const result = await platformService.dbQuery("SELECT * FROM accounts");
|
||||
const result = await platformService.dbQuery("SELECT did FROM accounts");
|
||||
|
||||
let accounts: Account[] = [];
|
||||
let dids: string[] = [];
|
||||
if (result?.values?.length) {
|
||||
accounts = result.values.map((row) => {
|
||||
const account = parseJsonField(row, {}) as Account;
|
||||
return {
|
||||
id: account.id,
|
||||
dateCreated: account.dateCreated || "",
|
||||
derivationPath: account.derivationPath || "",
|
||||
did: account.did || "",
|
||||
identity: account.identity || "",
|
||||
mnemonic: account.mnemonic || "",
|
||||
passkeyCredIdHex: account.passkeyCredIdHex || "",
|
||||
publicKeyHex: account.publicKeyHex || "",
|
||||
} as Account;
|
||||
});
|
||||
dids = result.values.map((row) => row[0] as string);
|
||||
}
|
||||
|
||||
logger.info(
|
||||
`[MigrationService] Retrieved ${accounts.length} accounts from SQLite`,
|
||||
`[MigrationService] Retrieved ${dids.length} accounts from SQLite`,
|
||||
);
|
||||
return accounts;
|
||||
return dids;
|
||||
} catch (error) {
|
||||
logger.error("[MigrationService] Error retrieving SQLite accounts:", error);
|
||||
throw new Error(`Failed to retrieve SQLite accounts: ${error}`);
|
||||
@@ -532,6 +494,7 @@ export async function compareDatabases(): Promise<DataComparison> {
|
||||
function compareContacts(dexieContacts: Contact[], sqliteContacts: Contact[]) {
|
||||
const added: Contact[] = [];
|
||||
const modified: Contact[] = [];
|
||||
const unmodified: Contact[] = [];
|
||||
const missing: Contact[] = [];
|
||||
|
||||
// Find contacts that exist in Dexie but not in SQLite
|
||||
@@ -543,6 +506,8 @@ function compareContacts(dexieContacts: Contact[], sqliteContacts: Contact[]) {
|
||||
added.push(dexieContact);
|
||||
} else if (!contactsEqual(dexieContact, sqliteContact)) {
|
||||
modified.push(dexieContact);
|
||||
} else {
|
||||
unmodified.push(dexieContact);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -554,7 +519,7 @@ function compareContacts(dexieContacts: Contact[], sqliteContacts: Contact[]) {
|
||||
}
|
||||
}
|
||||
|
||||
return { added, modified, missing };
|
||||
return { added, modified, unmodified, missing };
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -588,27 +553,30 @@ function compareSettings(
|
||||
) {
|
||||
const added: Settings[] = [];
|
||||
const modified: Settings[] = [];
|
||||
const unmodified: Settings[] = [];
|
||||
const missing: Settings[] = [];
|
||||
|
||||
// Find settings that exist in Dexie but not in SQLite
|
||||
for (const dexieSetting of dexieSettings) {
|
||||
const sqliteSetting = sqliteSettings.find((s) => s.id === dexieSetting.id);
|
||||
const sqliteSetting = sqliteSettings.find((s) => s.accountDid === dexieSetting.accountDid);
|
||||
if (!sqliteSetting) {
|
||||
added.push(dexieSetting);
|
||||
} else if (!settingsEqual(dexieSetting, sqliteSetting)) {
|
||||
modified.push(dexieSetting);
|
||||
} else {
|
||||
unmodified.push(dexieSetting);
|
||||
}
|
||||
}
|
||||
|
||||
// Find settings that exist in SQLite but not in Dexie
|
||||
for (const sqliteSetting of sqliteSettings) {
|
||||
const dexieSetting = dexieSettings.find((s) => s.id === sqliteSetting.id);
|
||||
const dexieSetting = dexieSettings.find((s) => s.accountDid === sqliteSetting.accountDid);
|
||||
if (!dexieSetting) {
|
||||
missing.push(sqliteSetting);
|
||||
}
|
||||
}
|
||||
|
||||
return { added, modified, missing };
|
||||
return { added, modified, unmodified, missing };
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -623,11 +591,11 @@ function compareSettings(
|
||||
*
|
||||
* @function compareAccounts
|
||||
* @param {Account[]} dexieAccounts - Accounts from Dexie database
|
||||
* @param {Account[]} sqliteAccounts - Accounts from SQLite database
|
||||
* @param {Account[]} sqliteDids - Accounts from SQLite database
|
||||
* @returns {Object} Object containing added, modified, and missing accounts
|
||||
* @returns {Account[]} returns.added - Accounts in Dexie but not SQLite
|
||||
* @returns {Account[]} returns.modified - Accounts that differ between databases
|
||||
* @returns {Account[]} returns.missing - Accounts in SQLite but not Dexie
|
||||
* @returns {Account[]} returns.modified - always 0 because we don't check
|
||||
* @returns {string[]} returns.missing - Accounts in SQLite but not Dexie
|
||||
* @example
|
||||
* ```typescript
|
||||
* const differences = compareAccounts(dexieAccounts, sqliteAccounts);
|
||||
@@ -636,30 +604,30 @@ function compareSettings(
|
||||
* console.log(`Missing: ${differences.missing.length}`);
|
||||
* ```
|
||||
*/
|
||||
function compareAccounts(dexieAccounts: Account[], sqliteAccounts: Account[]) {
|
||||
function compareAccounts(dexieAccounts: Account[], sqliteDids: string[]) {
|
||||
const added: Account[] = [];
|
||||
const modified: Account[] = [];
|
||||
const missing: Account[] = [];
|
||||
const unmodified: Account[] = [];
|
||||
const missing: string[] = [];
|
||||
|
||||
// Find accounts that exist in Dexie but not in SQLite
|
||||
for (const dexieAccount of dexieAccounts) {
|
||||
const sqliteAccount = sqliteAccounts.find((a) => a.id === dexieAccount.id);
|
||||
if (!sqliteAccount) {
|
||||
const sqliteDid = sqliteDids.find((a) => a === dexieAccount.did);
|
||||
if (!sqliteDid) {
|
||||
added.push(dexieAccount);
|
||||
} else if (!accountsEqual(dexieAccount, sqliteAccount)) {
|
||||
modified.push(dexieAccount);
|
||||
} else {
|
||||
unmodified.push(dexieAccount);
|
||||
}
|
||||
}
|
||||
|
||||
// Find accounts that exist in SQLite but not in Dexie
|
||||
for (const sqliteAccount of sqliteAccounts) {
|
||||
const dexieAccount = dexieAccounts.find((a) => a.id === sqliteAccount.id);
|
||||
for (const sqliteDid of sqliteDids) {
|
||||
const dexieAccount = dexieAccounts.find((a) => a.did === sqliteDid);
|
||||
if (!dexieAccount) {
|
||||
missing.push(sqliteAccount);
|
||||
missing.push(sqliteDid);
|
||||
}
|
||||
}
|
||||
|
||||
return { added, modified, missing };
|
||||
return { added, unmodified, missing };
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -688,15 +656,15 @@ function compareAccounts(dexieAccounts: Account[], sqliteAccounts: Account[]) {
|
||||
*/
|
||||
function contactsEqual(contact1: Contact, contact2: Contact): boolean {
|
||||
return (
|
||||
contact1.did === contact2.did &&
|
||||
contact1.name === contact2.name &&
|
||||
contact1.notes === contact2.notes &&
|
||||
contact1.profileImageUrl === contact2.profileImageUrl &&
|
||||
contact1.publicKeyBase64 === contact2.publicKeyBase64 &&
|
||||
contact1.nextPubKeyHashB64 === contact2.nextPubKeyHashB64 &&
|
||||
contact1.seesMe === contact2.seesMe &&
|
||||
contact1.registered === contact2.registered &&
|
||||
JSON.stringify(contact1.contactMethods) ===
|
||||
contact1.did == contact2.did &&
|
||||
contact1.name == contact2.name &&
|
||||
contact1.notes == contact2.notes &&
|
||||
contact1.profileImageUrl == contact2.profileImageUrl &&
|
||||
contact1.publicKeyBase64 == contact2.publicKeyBase64 &&
|
||||
contact1.nextPubKeyHashB64 == contact2.nextPubKeyHashB64 &&
|
||||
contact1.seesMe == contact2.seesMe &&
|
||||
contact1.registered == contact2.registered &&
|
||||
JSON.stringify(contact1.contactMethods) ==
|
||||
JSON.stringify(contact2.contactMethods)
|
||||
);
|
||||
}
|
||||
@@ -727,38 +695,38 @@ function contactsEqual(contact1: Contact, contact2: Contact): boolean {
|
||||
*/
|
||||
function settingsEqual(settings1: Settings, settings2: Settings): boolean {
|
||||
return (
|
||||
settings1.id === settings2.id &&
|
||||
settings1.accountDid === settings2.accountDid &&
|
||||
settings1.activeDid === settings2.activeDid &&
|
||||
settings1.apiServer === settings2.apiServer &&
|
||||
settings1.filterFeedByNearby === settings2.filterFeedByNearby &&
|
||||
settings1.filterFeedByVisible === settings2.filterFeedByVisible &&
|
||||
settings1.finishedOnboarding === settings2.finishedOnboarding &&
|
||||
settings1.firstName === settings2.firstName &&
|
||||
settings1.hideRegisterPromptOnNewContact ===
|
||||
settings1.id == settings2.id &&
|
||||
settings1.accountDid == settings2.accountDid &&
|
||||
settings1.activeDid == settings2.activeDid &&
|
||||
settings1.apiServer == settings2.apiServer &&
|
||||
settings1.filterFeedByNearby == settings2.filterFeedByNearby &&
|
||||
settings1.filterFeedByVisible == settings2.filterFeedByVisible &&
|
||||
settings1.finishedOnboarding == settings2.finishedOnboarding &&
|
||||
settings1.firstName == settings2.firstName &&
|
||||
settings1.hideRegisterPromptOnNewContact ==
|
||||
settings2.hideRegisterPromptOnNewContact &&
|
||||
settings1.isRegistered === settings2.isRegistered &&
|
||||
settings1.lastName === settings2.lastName &&
|
||||
settings1.lastAckedOfferToUserJwtId ===
|
||||
settings1.isRegistered == settings2.isRegistered &&
|
||||
settings1.lastName == settings2.lastName &&
|
||||
settings1.lastAckedOfferToUserJwtId ==
|
||||
settings2.lastAckedOfferToUserJwtId &&
|
||||
settings1.lastAckedOfferToUserProjectsJwtId ===
|
||||
settings1.lastAckedOfferToUserProjectsJwtId ==
|
||||
settings2.lastAckedOfferToUserProjectsJwtId &&
|
||||
settings1.lastNotifiedClaimId === settings2.lastNotifiedClaimId &&
|
||||
settings1.lastViewedClaimId === settings2.lastViewedClaimId &&
|
||||
settings1.notifyingNewActivityTime === settings2.notifyingNewActivityTime &&
|
||||
settings1.notifyingReminderMessage === settings2.notifyingReminderMessage &&
|
||||
settings1.notifyingReminderTime === settings2.notifyingReminderTime &&
|
||||
settings1.partnerApiServer === settings2.partnerApiServer &&
|
||||
settings1.passkeyExpirationMinutes === settings2.passkeyExpirationMinutes &&
|
||||
settings1.profileImageUrl === settings2.profileImageUrl &&
|
||||
settings1.showContactGivesInline === settings2.showContactGivesInline &&
|
||||
settings1.showGeneralAdvanced === settings2.showGeneralAdvanced &&
|
||||
settings1.showShortcutBvc === settings2.showShortcutBvc &&
|
||||
settings1.vapid === settings2.vapid &&
|
||||
settings1.warnIfProdServer === settings2.warnIfProdServer &&
|
||||
settings1.warnIfTestServer === settings2.warnIfTestServer &&
|
||||
settings1.webPushServer === settings2.webPushServer &&
|
||||
JSON.stringify(settings1.searchBoxes) ===
|
||||
settings1.lastNotifiedClaimId == settings2.lastNotifiedClaimId &&
|
||||
settings1.lastViewedClaimId == settings2.lastViewedClaimId &&
|
||||
settings1.notifyingNewActivityTime == settings2.notifyingNewActivityTime &&
|
||||
settings1.notifyingReminderMessage == settings2.notifyingReminderMessage &&
|
||||
settings1.notifyingReminderTime == settings2.notifyingReminderTime &&
|
||||
settings1.partnerApiServer == settings2.partnerApiServer &&
|
||||
settings1.passkeyExpirationMinutes == settings2.passkeyExpirationMinutes &&
|
||||
settings1.profileImageUrl == settings2.profileImageUrl &&
|
||||
settings1.showContactGivesInline == settings2.showContactGivesInline &&
|
||||
settings1.showGeneralAdvanced == settings2.showGeneralAdvanced &&
|
||||
settings1.showShortcutBvc == settings2.showShortcutBvc &&
|
||||
settings1.vapid == settings2.vapid &&
|
||||
settings1.warnIfProdServer == settings2.warnIfProdServer &&
|
||||
settings1.warnIfTestServer == settings2.warnIfTestServer &&
|
||||
settings1.webPushServer == settings2.webPushServer &&
|
||||
JSON.stringify(settings1.searchBoxes) ==
|
||||
JSON.stringify(settings2.searchBoxes)
|
||||
);
|
||||
}
|
||||
@@ -830,23 +798,25 @@ export function generateComparisonYaml(comparison: DataComparison): string {
|
||||
dexieSettings: comparison.dexieSettings.length,
|
||||
sqliteSettings: comparison.sqliteSettings.filter(s => s.accountDid || s.activeDid).length,
|
||||
dexieAccounts: comparison.dexieAccounts.length,
|
||||
sqliteAccounts: comparison.sqliteAccounts.filter(a => a.did).length,
|
||||
sqliteAccounts: comparison.sqliteAccounts.filter(a => a).length,
|
||||
},
|
||||
differences: {
|
||||
contacts: {
|
||||
added: comparison.differences.contacts.added.length,
|
||||
modified: comparison.differences.contacts.modified.length,
|
||||
unmodified: comparison.differences.contacts.unmodified.length,
|
||||
missing: comparison.differences.contacts.missing.filter(c => c.did).length,
|
||||
},
|
||||
settings: {
|
||||
added: comparison.differences.settings.added.length,
|
||||
modified: comparison.differences.settings.modified.length,
|
||||
unmodified: comparison.differences.settings.unmodified.length,
|
||||
missing: comparison.differences.settings.missing.filter(s => s.accountDid || s.activeDid).length,
|
||||
},
|
||||
accounts: {
|
||||
added: comparison.differences.accounts.added.length,
|
||||
modified: comparison.differences.accounts.modified.length,
|
||||
missing: comparison.differences.accounts.missing.filter(a => a.did).length,
|
||||
unmodified: comparison.differences.accounts.unmodified.length,
|
||||
missing: comparison.differences.accounts.missing.filter(a => a).length,
|
||||
},
|
||||
},
|
||||
details: {
|
||||
@@ -888,15 +858,9 @@ export function generateComparisonYaml(comparison: DataComparison): string {
|
||||
hasIdentity: !!a.identity,
|
||||
hasMnemonic: !!a.mnemonic,
|
||||
})),
|
||||
sqlite: comparison.sqliteAccounts
|
||||
.filter(a => a.did)
|
||||
.map((a) => ({
|
||||
id: a.id,
|
||||
did: a.did,
|
||||
dateCreated: a.dateCreated,
|
||||
hasIdentity: !!a.identity,
|
||||
hasMnemonic: !!a.mnemonic,
|
||||
})),
|
||||
sqlite: comparison.sqliteAccounts.map((a) => ({
|
||||
did: a,
|
||||
})),
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
</div>
|
||||
<div>
|
||||
<p v-if="downloadMnemonic" class="text-green-500">
|
||||
Here is your seed. Write it down!
|
||||
Here is your seed for account {{ downloadMnemonicAddress?.substring('did:ethr:0x'.length).substring(0, 3) }} -- write it down!
|
||||
<br />
|
||||
{{ downloadMnemonic }}
|
||||
</p>
|
||||
@@ -506,15 +506,15 @@
|
||||
>
|
||||
<div class="flex items-center">
|
||||
<IconRenderer
|
||||
icon-name="edit"
|
||||
icon-name="check"
|
||||
svg-class="h-5 w-5 text-yellow-600 mr-2"
|
||||
/>
|
||||
<span class="text-sm font-medium text-yellow-900"
|
||||
>Modify</span
|
||||
>Unmodified</span
|
||||
>
|
||||
</div>
|
||||
<span class="text-sm font-bold text-yellow-900">{{
|
||||
comparison.differences.accounts.modified.length
|
||||
comparison.differences.accounts.unmodified.length
|
||||
}}</span>
|
||||
</div>
|
||||
|
||||
@@ -559,48 +559,44 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modify Accounts -->
|
||||
<!-- Unmodified Accounts -->
|
||||
<div
|
||||
v-if="comparison.differences.accounts.modified.length > 0"
|
||||
v-if="comparison.differences.accounts.unmodified.length > 0"
|
||||
class="mt-4"
|
||||
>
|
||||
<h4 class="text-sm font-medium text-gray-900 mb-2">
|
||||
Modify Accounts ({{ comparison.differences.accounts.modified.length }}):
|
||||
Unmodified Accounts ({{ comparison.differences.accounts.unmodified.length }}):
|
||||
</h4>
|
||||
<div class="space-y-1">
|
||||
<div
|
||||
v-for="account in comparison.differences.accounts.modified"
|
||||
:key="account.id"
|
||||
class="text-xs text-gray-600 bg-gray-50 p-2 rounded"
|
||||
>
|
||||
<div class="font-medium">ID: {{ account.id }}</div>
|
||||
<div class="text-gray-500">{{ account.did }}</div>
|
||||
<div class="text-gray-400">Created: {{ account.dateCreated }}</div>
|
||||
<div class="text-gray-400">Has Identity: {{ getAccountHasIdentity(account) ? 'Yes' : 'No' }}</div>
|
||||
<div class="text-gray-400">Has Mnemonic: {{ getAccountHasMnemonic(account) ? 'Yes' : 'No' }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="space-y-1">
|
||||
<div
|
||||
v-for="account in comparison.differences.accounts.unmodified"
|
||||
:key="account.id"
|
||||
class="text-xs text-gray-600 bg-gray-50 p-2 rounded"
|
||||
>
|
||||
<div class="font-medium">ID: {{ account.id }}</div>
|
||||
<div class="text-gray-500">{{ account.did }}</div>
|
||||
<div class="text-gray-400">Created: {{ account.dateCreated }}</div>
|
||||
<div class="text-gray-400">Has Identity: {{ getAccountHasIdentity(account) ? 'Yes' : 'No' }}</div>
|
||||
<div class="text-gray-400">Has Mnemonic: {{ getAccountHasMnemonic(account) ? 'Yes' : 'No' }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Keep Accounts -->
|
||||
<div
|
||||
v-if="comparison.differences.accounts.missing.filter(a => a.did).length > 0"
|
||||
v-if="comparison.differences.accounts.missing.filter(a => a).length > 0"
|
||||
class="mt-4"
|
||||
>
|
||||
<h4 class="text-sm font-medium text-gray-900 mb-2">
|
||||
Keep Accounts ({{ comparison.differences.accounts.missing.filter(a => a.did).length }}):
|
||||
Keep Accounts ({{ comparison.differences.accounts.missing.filter(a => a).length }}):
|
||||
</h4>
|
||||
<div class="space-y-1">
|
||||
<div
|
||||
v-for="account in comparison.differences.accounts.missing.filter(a => a.did)"
|
||||
:key="account.id"
|
||||
v-for="did in comparison.differences.accounts.missing.filter(a => a)"
|
||||
:key="did"
|
||||
class="text-xs text-gray-600 bg-gray-50 p-2 rounded"
|
||||
>
|
||||
<div class="font-medium">ID: {{ account.id }}</div>
|
||||
<div class="text-gray-500">{{ account.did }}</div>
|
||||
<div class="text-gray-400">Created: {{ account.dateCreated }}</div>
|
||||
<div class="text-gray-400">Has Identity: {{ getAccountHasIdentity(account) ? 'Yes' : 'No' }}</div>
|
||||
<div class="text-gray-400">Has Mnemonic: {{ getAccountHasMnemonic(account) ? 'Yes' : 'No' }}</div>
|
||||
<div class="text-gray-500">{{ did }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -647,6 +643,23 @@
|
||||
}}</span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="flex items-center justify-between p-3 bg-yellow-50 rounded-lg"
|
||||
>
|
||||
<div class="flex items-center">
|
||||
<IconRenderer
|
||||
icon-name="check"
|
||||
svg-class="h-5 w-5 text-yellow-600 mr-2"
|
||||
/>
|
||||
<span class="text-sm font-medium text-yellow-900"
|
||||
>Unmodified</span
|
||||
>
|
||||
</div>
|
||||
<span class="text-sm font-bold text-yellow-900">{{
|
||||
comparison.differences.settings.unmodified.length
|
||||
}}</span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="flex items-center justify-between p-3 bg-red-50 rounded-lg"
|
||||
>
|
||||
@@ -707,6 +720,27 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Unmodified Settings -->
|
||||
<div
|
||||
v-if="comparison.differences.settings.unmodified.length > 0"
|
||||
class="mt-4"
|
||||
>
|
||||
<h4 class="text-sm font-medium text-gray-900 mb-2">
|
||||
Unmodified Settings ({{ comparison.differences.settings.unmodified.length }}):
|
||||
</h4>
|
||||
</div>
|
||||
<div class="space-y-1">
|
||||
<div
|
||||
v-for="setting in comparison.differences.settings.unmodified"
|
||||
:key="setting.id"
|
||||
class="text-xs text-gray-600 bg-gray-50 p-2 rounded"
|
||||
>
|
||||
<div class="font-medium">{{ getSettingDisplayName(setting) }}</div>
|
||||
<div class="text-gray-500">ID: {{ setting.id }}</div>
|
||||
<div class="text-gray-400">Registered: {{ setting.isRegistered ? 'Yes' : 'No' }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Keep Settings -->
|
||||
<div
|
||||
v-if="comparison.differences.settings.missing.filter(s => s.accountDid || s.activeDid).length > 0"
|
||||
@@ -770,6 +804,23 @@
|
||||
}}</span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="flex items-center justify-between p-3 bg-yellow-50 rounded-lg"
|
||||
>
|
||||
<div class="flex items-center">
|
||||
<IconRenderer
|
||||
icon-name="check"
|
||||
svg-class="h-5 w-5 text-yellow-600 mr-2"
|
||||
/>
|
||||
<span class="text-sm font-medium text-yellow-900"
|
||||
>Unmodified</span
|
||||
>
|
||||
</div>
|
||||
<span class="text-sm font-bold text-yellow-900">{{
|
||||
comparison.differences.contacts.unmodified.length
|
||||
}}</span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="flex items-center justify-between p-3 bg-red-50 rounded-lg"
|
||||
>
|
||||
@@ -830,6 +881,27 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Unmodified Contacts -->
|
||||
<div
|
||||
v-if="comparison.differences.contacts.unmodified.length > 0"
|
||||
class="mt-4"
|
||||
>
|
||||
<h4 class="text-sm font-medium text-gray-900 mb-2">
|
||||
Unmodified Contacts ({{ comparison.differences.contacts.unmodified.length }}):
|
||||
</h4>
|
||||
</div>
|
||||
<div class="space-y-1">
|
||||
<div
|
||||
v-for="contact in comparison.differences.contacts.unmodified"
|
||||
:key="contact.did"
|
||||
class="text-xs text-gray-600 bg-gray-50 p-2 rounded"
|
||||
>
|
||||
<div class="font-medium">{{ contact.name || '<empty>' }}</div>
|
||||
<div class="text-gray-500">{{ contact.did }}</div>
|
||||
<div class="text-gray-400">{{ contact.contactMethods?.length || 0 }} contact methods</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Keep Contacts -->
|
||||
<div
|
||||
v-if="comparison.differences.contacts.missing.filter(c => c.did).length > 0"
|
||||
@@ -871,7 +943,6 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { ref } from "vue";
|
||||
import { Component, Vue } from "vue-facing-decorator";
|
||||
import { useClipboard } from "@vueuse/core";
|
||||
|
||||
@@ -923,6 +994,7 @@ export default class DatabaseMigration extends Vue {
|
||||
private cannotfindMainAccount = false;
|
||||
private downloadSettingsContactsBlob?: Blob;
|
||||
private downloadMnemonic?: string;
|
||||
private downloadMnemonicAddress?: string;
|
||||
private hasMultipleMnemonics = false;
|
||||
private isLoading = false;
|
||||
private loadingMessage = "";
|
||||
@@ -1024,6 +1096,7 @@ export default class DatabaseMigration extends Vue {
|
||||
}
|
||||
if (primaryAccount) {
|
||||
this.downloadMnemonic = primaryAccount.mnemonic;
|
||||
this.downloadMnemonicAddress = primaryAccount.did;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -182,6 +182,15 @@
|
||||
>
|
||||
Accounts
|
||||
</button>
|
||||
<button
|
||||
class="text-sm text-blue-600 hover:text-blue-800 underline"
|
||||
@click="
|
||||
sqlQuery = 'SELECT * FROM contacts;';
|
||||
executeSql();
|
||||
"
|
||||
>
|
||||
Contacts
|
||||
</button>
|
||||
<button
|
||||
class="text-sm text-blue-600 hover:text-blue-800 underline"
|
||||
@click="
|
||||
|
||||
Reference in New Issue
Block a user