forked from trent_larson/crowd-funder-for-time-pwa
fix linting
This commit is contained in:
@@ -21,7 +21,7 @@ export interface Contact {
|
|||||||
|
|
||||||
export type ContactWithJsonStrings = Contact & {
|
export type ContactWithJsonStrings = Contact & {
|
||||||
contactMethods?: string;
|
contactMethods?: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
export const ContactSchema = {
|
export const ContactSchema = {
|
||||||
contacts: "&did, name", // no need to key by other things
|
contacts: "&did, name", // no need to key by other things
|
||||||
|
|||||||
@@ -26,10 +26,19 @@ import "dexie-export-import";
|
|||||||
import { PlatformServiceFactory } from "./PlatformServiceFactory";
|
import { PlatformServiceFactory } from "./PlatformServiceFactory";
|
||||||
import { db, accountsDBPromise } from "../db/index";
|
import { db, accountsDBPromise } from "../db/index";
|
||||||
import { Contact, ContactMethod } from "../db/tables/contacts";
|
import { Contact, ContactMethod } from "../db/tables/contacts";
|
||||||
import { Settings, MASTER_SETTINGS_KEY, BoundingBox } from "../db/tables/settings";
|
import {
|
||||||
|
Settings,
|
||||||
|
MASTER_SETTINGS_KEY,
|
||||||
|
BoundingBox,
|
||||||
|
} from "../db/tables/settings";
|
||||||
import { Account } from "../db/tables/accounts";
|
import { Account } from "../db/tables/accounts";
|
||||||
import { logger } from "../utils/logger";
|
import { logger } from "../utils/logger";
|
||||||
import { mapColumnsToValues, parseJsonField, generateUpdateStatement, generateInsertStatement } from "../db/databaseUtil";
|
import {
|
||||||
|
mapColumnsToValues,
|
||||||
|
parseJsonField,
|
||||||
|
generateUpdateStatement,
|
||||||
|
generateInsertStatement,
|
||||||
|
} from "../db/databaseUtil";
|
||||||
import { importFromMnemonic } from "../libs/util";
|
import { importFromMnemonic } from "../libs/util";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -186,12 +195,18 @@ export async function getSqliteContacts(): Promise<Contact[]> {
|
|||||||
|
|
||||||
let contacts: Contact[] = [];
|
let contacts: Contact[] = [];
|
||||||
if (result?.values?.length) {
|
if (result?.values?.length) {
|
||||||
const preContacts = mapColumnsToValues(result.columns, result.values) as unknown 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.
|
// 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.
|
// But we started it, and it should be known everywhere, so we're keeping it.
|
||||||
contacts = preContacts.map((contact) => {
|
contacts = preContacts.map((contact) => {
|
||||||
if (contact.contactMethods) {
|
if (contact.contactMethods) {
|
||||||
contact.contactMethods = parseJsonField(contact.contactMethods, []) as ContactMethod[];
|
contact.contactMethods = parseJsonField(
|
||||||
|
contact.contactMethods,
|
||||||
|
[],
|
||||||
|
) as ContactMethod[];
|
||||||
}
|
}
|
||||||
return contact;
|
return contact;
|
||||||
});
|
});
|
||||||
@@ -212,7 +227,7 @@ export async function getSqliteContacts(): Promise<Contact[]> {
|
|||||||
*
|
*
|
||||||
* This function connects to the Dexie database and retrieves all settings
|
* This function connects to the Dexie database and retrieves all settings
|
||||||
* records.
|
* records.
|
||||||
*
|
*
|
||||||
* Settings include both master settings (id=1) and account-specific settings
|
* Settings include both master settings (id=1) and account-specific settings
|
||||||
* that override the master settings for particular user accounts.
|
* that override the master settings for particular user accounts.
|
||||||
*
|
*
|
||||||
@@ -275,16 +290,21 @@ export async function getSqliteSettings(): Promise<Settings[]> {
|
|||||||
|
|
||||||
let settings: Settings[] = [];
|
let settings: Settings[] = [];
|
||||||
if (result?.values?.length) {
|
if (result?.values?.length) {
|
||||||
const presettings =
|
const presettings = mapColumnsToValues(
|
||||||
mapColumnsToValues(result.columns, result.values) as Settings[];
|
result.columns,
|
||||||
|
result.values,
|
||||||
|
) as Settings[];
|
||||||
// This is redundant since absurd-sql auto-parses JSON strings to objects.
|
// 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.
|
// But we started it, and it should be known everywhere, so we're keeping it.
|
||||||
settings = presettings.map((setting) => {
|
settings = presettings.map((setting) => {
|
||||||
if (setting.searchBoxes) {
|
if (setting.searchBoxes) {
|
||||||
setting.searchBoxes = parseJsonField(setting.searchBoxes, []) as Array<{ name: string, bbox: BoundingBox }>;
|
setting.searchBoxes = parseJsonField(
|
||||||
|
setting.searchBoxes,
|
||||||
|
[],
|
||||||
|
) as Array<{ name: string; bbox: BoundingBox }>;
|
||||||
}
|
}
|
||||||
return setting;
|
return setting;
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info(
|
logger.info(
|
||||||
@@ -557,7 +577,9 @@ function compareSettings(
|
|||||||
|
|
||||||
// Find settings that exist in Dexie but not in SQLite
|
// Find settings that exist in Dexie but not in SQLite
|
||||||
for (const dexieSetting of dexieSettings) {
|
for (const dexieSetting of dexieSettings) {
|
||||||
const sqliteSetting = sqliteSettings.find((s) => s.accountDid == dexieSetting.accountDid);
|
const sqliteSetting = sqliteSettings.find(
|
||||||
|
(s) => s.accountDid == dexieSetting.accountDid,
|
||||||
|
);
|
||||||
if (!sqliteSetting) {
|
if (!sqliteSetting) {
|
||||||
added.push(dexieSetting);
|
added.push(dexieSetting);
|
||||||
} else if (!settingsEqual(dexieSetting, sqliteSetting)) {
|
} else if (!settingsEqual(dexieSetting, sqliteSetting)) {
|
||||||
@@ -569,7 +591,9 @@ function compareSettings(
|
|||||||
|
|
||||||
// Find settings that exist in SQLite but not in Dexie
|
// Find settings that exist in SQLite but not in Dexie
|
||||||
for (const sqliteSetting of sqliteSettings) {
|
for (const sqliteSetting of sqliteSettings) {
|
||||||
const dexieSetting = dexieSettings.find((s) => s.accountDid == sqliteSetting.accountDid);
|
const dexieSetting = dexieSettings.find(
|
||||||
|
(s) => s.accountDid == sqliteSetting.accountDid,
|
||||||
|
);
|
||||||
if (!dexieSetting) {
|
if (!dexieSetting) {
|
||||||
missing.push(sqliteSetting);
|
missing.push(sqliteSetting);
|
||||||
}
|
}
|
||||||
@@ -654,22 +678,29 @@ function compareAccounts(dexieAccounts: Account[], sqliteDids: string[]) {
|
|||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
function contactsEqual(contact1: Contact, contact2: Contact): boolean {
|
function contactsEqual(contact1: Contact, contact2: Contact): boolean {
|
||||||
const ifEmpty = (arg: any, def: any) => !!arg ? arg : def;
|
const ifEmpty = (arg: any, def: any) => (arg ? arg : def);
|
||||||
const contact1Methods =
|
const contact1Methods =
|
||||||
contact1.contactMethods && Array.isArray(contact1.contactMethods) && contact1.contactMethods.length > 0
|
contact1.contactMethods &&
|
||||||
? JSON.stringify(contact1.contactMethods)
|
Array.isArray(contact1.contactMethods) &&
|
||||||
: "[]";
|
contact1.contactMethods.length > 0
|
||||||
|
? JSON.stringify(contact1.contactMethods)
|
||||||
|
: "[]";
|
||||||
const contact2Methods =
|
const contact2Methods =
|
||||||
contact2.contactMethods && Array.isArray(contact2.contactMethods) && contact2.contactMethods.length > 0
|
contact2.contactMethods &&
|
||||||
? JSON.stringify(contact2.contactMethods)
|
Array.isArray(contact2.contactMethods) &&
|
||||||
: "[]";
|
contact2.contactMethods.length > 0
|
||||||
|
? JSON.stringify(contact2.contactMethods)
|
||||||
|
: "[]";
|
||||||
return (
|
return (
|
||||||
ifEmpty(contact1.did, "") == ifEmpty(contact2.did, "") &&
|
ifEmpty(contact1.did, "") == ifEmpty(contact2.did, "") &&
|
||||||
ifEmpty(contact1.name, "") == ifEmpty(contact2.name, "") &&
|
ifEmpty(contact1.name, "") == ifEmpty(contact2.name, "") &&
|
||||||
ifEmpty(contact1.notes, "") == ifEmpty(contact2.notes, "") &&
|
ifEmpty(contact1.notes, "") == ifEmpty(contact2.notes, "") &&
|
||||||
ifEmpty(contact1.profileImageUrl, "") == ifEmpty(contact2.profileImageUrl, "") &&
|
ifEmpty(contact1.profileImageUrl, "") ==
|
||||||
ifEmpty(contact1.publicKeyBase64, "") == ifEmpty(contact2.publicKeyBase64, "") &&
|
ifEmpty(contact2.profileImageUrl, "") &&
|
||||||
ifEmpty(contact1.nextPubKeyHashB64, "") == ifEmpty(contact2.nextPubKeyHashB64, "") &&
|
ifEmpty(contact1.publicKeyBase64, "") ==
|
||||||
|
ifEmpty(contact2.publicKeyBase64, "") &&
|
||||||
|
ifEmpty(contact1.nextPubKeyHashB64, "") ==
|
||||||
|
ifEmpty(contact2.nextPubKeyHashB64, "") &&
|
||||||
!!contact1.seesMe == !!contact2.seesMe &&
|
!!contact1.seesMe == !!contact2.seesMe &&
|
||||||
!!contact1.registered == !!contact2.registered &&
|
!!contact1.registered == !!contact2.registered &&
|
||||||
contact1Methods == contact2Methods
|
contact1Methods == contact2Methods
|
||||||
@@ -762,18 +793,21 @@ function settingsEqual(settings1: Settings, settings2: Settings): boolean {
|
|||||||
* }
|
* }
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
function accountsEqual(account1: Account, account2: Account): boolean {
|
//
|
||||||
return (
|
// unused
|
||||||
account1.id === account2.id &&
|
//
|
||||||
account1.dateCreated === account2.dateCreated &&
|
// function accountsEqual(account1: Account, account2: Account): boolean {
|
||||||
account1.derivationPath === account2.derivationPath &&
|
// return (
|
||||||
account1.did === account2.did &&
|
// account1.id === account2.id &&
|
||||||
account1.identity === account2.identity &&
|
// account1.dateCreated === account2.dateCreated &&
|
||||||
account1.mnemonic === account2.mnemonic &&
|
// account1.derivationPath === account2.derivationPath &&
|
||||||
account1.passkeyCredIdHex === account2.passkeyCredIdHex &&
|
// account1.did === account2.did &&
|
||||||
account1.publicKeyHex === account2.publicKeyHex
|
// account1.identity === account2.identity &&
|
||||||
);
|
// account1.mnemonic === account2.mnemonic &&
|
||||||
}
|
// account1.passkeyCredIdHex === account2.passkeyCredIdHex &&
|
||||||
|
// account1.publicKeyHex === account2.publicKeyHex
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates YAML-formatted comparison data
|
* Generates YAML-formatted comparison data
|
||||||
@@ -801,58 +835,64 @@ export function generateComparisonYaml(comparison: DataComparison): string {
|
|||||||
const yaml = {
|
const yaml = {
|
||||||
summary: {
|
summary: {
|
||||||
dexieContacts: comparison.dexieContacts.length,
|
dexieContacts: comparison.dexieContacts.length,
|
||||||
sqliteContacts: comparison.sqliteContacts.filter(c => c.did).length,
|
sqliteContacts: comparison.sqliteContacts.filter((c) => c.did).length,
|
||||||
dexieSettings: comparison.dexieSettings.length,
|
dexieSettings: comparison.dexieSettings.length,
|
||||||
sqliteSettings: comparison.sqliteSettings.filter(s => s.accountDid || s.activeDid).length,
|
sqliteSettings: comparison.sqliteSettings.filter(
|
||||||
|
(s) => s.accountDid || s.activeDid,
|
||||||
|
).length,
|
||||||
dexieAccounts: comparison.dexieAccounts.length,
|
dexieAccounts: comparison.dexieAccounts.length,
|
||||||
sqliteAccounts: comparison.sqliteAccounts.filter(a => a).length,
|
sqliteAccounts: comparison.sqliteAccounts.filter((a) => a).length,
|
||||||
},
|
},
|
||||||
differences: {
|
differences: {
|
||||||
contacts: {
|
contacts: {
|
||||||
added: comparison.differences.contacts.added.length,
|
added: comparison.differences.contacts.added.length,
|
||||||
modified: comparison.differences.contacts.modified.length,
|
modified: comparison.differences.contacts.modified.length,
|
||||||
unmodified: comparison.differences.contacts.unmodified.length,
|
unmodified: comparison.differences.contacts.unmodified.length,
|
||||||
missing: comparison.differences.contacts.missing.filter(c => c.did).length,
|
missing: comparison.differences.contacts.missing.filter((c) => c.did)
|
||||||
|
.length,
|
||||||
},
|
},
|
||||||
settings: {
|
settings: {
|
||||||
added: comparison.differences.settings.added.length,
|
added: comparison.differences.settings.added.length,
|
||||||
modified: comparison.differences.settings.modified.length,
|
modified: comparison.differences.settings.modified.length,
|
||||||
unmodified: comparison.differences.settings.unmodified.length,
|
unmodified: comparison.differences.settings.unmodified.length,
|
||||||
missing: comparison.differences.settings.missing.filter(s => s.accountDid || s.activeDid).length,
|
missing: comparison.differences.settings.missing.filter(
|
||||||
|
(s) => s.accountDid || s.activeDid,
|
||||||
|
).length,
|
||||||
},
|
},
|
||||||
accounts: {
|
accounts: {
|
||||||
added: comparison.differences.accounts.added.length,
|
added: comparison.differences.accounts.added.length,
|
||||||
unmodified: comparison.differences.accounts.unmodified.length,
|
unmodified: comparison.differences.accounts.unmodified.length,
|
||||||
missing: comparison.differences.accounts.missing.filter(a => a).length,
|
missing: comparison.differences.accounts.missing.filter((a) => a)
|
||||||
|
.length,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
details: {
|
details: {
|
||||||
contacts: {
|
contacts: {
|
||||||
dexie: comparison.dexieContacts.map((c) => ({
|
dexie: comparison.dexieContacts.map((c) => ({
|
||||||
did: c.did,
|
did: c.did,
|
||||||
name: c.name || '<empty>',
|
name: c.name || "<empty>",
|
||||||
contactMethods: (c.contactMethods || []).length,
|
contactMethods: (c.contactMethods || []).length,
|
||||||
})),
|
})),
|
||||||
sqlite: comparison.sqliteContacts
|
sqlite: comparison.sqliteContacts
|
||||||
.filter(c => c.did)
|
.filter((c) => c.did)
|
||||||
.map((c) => ({
|
.map((c) => ({
|
||||||
did: c.did,
|
did: c.did,
|
||||||
name: c.name || '<empty>',
|
name: c.name || "<empty>",
|
||||||
contactMethods: (c.contactMethods || []).length,
|
contactMethods: (c.contactMethods || []).length,
|
||||||
})),
|
})),
|
||||||
},
|
},
|
||||||
settings: {
|
settings: {
|
||||||
dexie: comparison.dexieSettings.map((s) => ({
|
dexie: comparison.dexieSettings.map((s) => ({
|
||||||
id: s.id,
|
id: s.id,
|
||||||
type: s.id === MASTER_SETTINGS_KEY ? 'master' : 'account',
|
type: s.id === MASTER_SETTINGS_KEY ? "master" : "account",
|
||||||
did: s.activeDid || s.accountDid,
|
did: s.activeDid || s.accountDid,
|
||||||
isRegistered: s.isRegistered || false,
|
isRegistered: s.isRegistered || false,
|
||||||
})),
|
})),
|
||||||
sqlite: comparison.sqliteSettings
|
sqlite: comparison.sqliteSettings
|
||||||
.filter(s => s.accountDid || s.activeDid)
|
.filter((s) => s.accountDid || s.activeDid)
|
||||||
.map((s) => ({
|
.map((s) => ({
|
||||||
id: s.id,
|
id: s.id,
|
||||||
type: s.id === MASTER_SETTINGS_KEY ? 'master' : 'account',
|
type: s.id === MASTER_SETTINGS_KEY ? "master" : "account",
|
||||||
did: s.activeDid || s.accountDid,
|
did: s.activeDid || s.accountDid,
|
||||||
isRegistered: s.isRegistered || false,
|
isRegistered: s.isRegistered || false,
|
||||||
})),
|
})),
|
||||||
@@ -1039,20 +1079,22 @@ export async function migrateSettings(): Promise<MigrationResult> {
|
|||||||
dexieSettings: dexieSettings.length,
|
dexieSettings: dexieSettings.length,
|
||||||
});
|
});
|
||||||
const platformService = PlatformServiceFactory.getInstance();
|
const platformService = PlatformServiceFactory.getInstance();
|
||||||
|
|
||||||
// Create an array of promises for all settings migrations
|
// Create an array of promises for all settings migrations
|
||||||
const migrationPromises = dexieSettings.map(async (setting) => {
|
const migrationPromises = dexieSettings.map(async (setting) => {
|
||||||
logger.info("[MigrationService] Starting to migrate settings", setting);
|
logger.info("[MigrationService] Starting to migrate settings", setting);
|
||||||
let sqliteSettingRaw: { columns: string[], values: unknown[][] } | undefined;
|
let sqliteSettingRaw:
|
||||||
|
| { columns: string[]; values: unknown[][] }
|
||||||
|
| undefined;
|
||||||
if (!setting.accountDid) {
|
if (!setting.accountDid) {
|
||||||
sqliteSettingRaw = await platformService.dbQuery(
|
sqliteSettingRaw = await platformService.dbQuery(
|
||||||
"SELECT * FROM settings WHERE accountDid is null"
|
"SELECT * FROM settings WHERE accountDid is null",
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
sqliteSettingRaw = await platformService.dbQuery(
|
sqliteSettingRaw = await platformService.dbQuery(
|
||||||
"SELECT * FROM settings WHERE accountDid = ?",
|
"SELECT * FROM settings WHERE accountDid = ?",
|
||||||
[setting.accountDid]
|
[setting.accountDid],
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
logger.info("[MigrationService] Migrating one set of settings:", {
|
logger.info("[MigrationService] Migrating one set of settings:", {
|
||||||
setting,
|
setting,
|
||||||
@@ -1060,9 +1102,11 @@ export async function migrateSettings(): Promise<MigrationResult> {
|
|||||||
});
|
});
|
||||||
if (sqliteSettingRaw?.values?.length) {
|
if (sqliteSettingRaw?.values?.length) {
|
||||||
// should cover the master settings, were accountDid is null
|
// should cover the master settings, were accountDid is null
|
||||||
const sqliteSettings = mapColumnsToValues(sqliteSettingRaw.columns, sqliteSettingRaw.values) as unknown as Settings[];
|
const sqliteSettings = mapColumnsToValues(
|
||||||
|
sqliteSettingRaw.columns,
|
||||||
|
sqliteSettingRaw.values,
|
||||||
|
) as unknown as Settings[];
|
||||||
const sqliteSetting = sqliteSettings[0];
|
const sqliteSetting = sqliteSettings[0];
|
||||||
console.log('sqliteSetting', sqliteSetting)
|
|
||||||
let conditional: string;
|
let conditional: string;
|
||||||
let preparams: unknown[];
|
let preparams: unknown[];
|
||||||
if (!setting.accountDid) {
|
if (!setting.accountDid) {
|
||||||
@@ -1076,16 +1120,16 @@ export async function migrateSettings(): Promise<MigrationResult> {
|
|||||||
sqliteSetting as unknown as Record<string, unknown>,
|
sqliteSetting as unknown as Record<string, unknown>,
|
||||||
"settings",
|
"settings",
|
||||||
conditional,
|
conditional,
|
||||||
preparams
|
preparams,
|
||||||
);
|
);
|
||||||
await platformService.dbExec(sql, params)
|
await platformService.dbExec(sql, params);
|
||||||
result.settingsMigrated++;
|
result.settingsMigrated++;
|
||||||
} else {
|
} else {
|
||||||
// insert new setting
|
// insert new setting
|
||||||
delete setting.activeDid; // ensure we don't set the activeDid (since master settings are an update and don't hit this case)
|
delete setting.activeDid; // ensure we don't set the activeDid (since master settings are an update and don't hit this case)
|
||||||
const { sql, params } = generateInsertStatement(
|
const { sql, params } = generateInsertStatement(
|
||||||
setting as unknown as Record<string, unknown>,
|
setting as unknown as Record<string, unknown>,
|
||||||
"settings"
|
"settings",
|
||||||
);
|
);
|
||||||
await platformService.dbExec(sql, params);
|
await platformService.dbExec(sql, params);
|
||||||
result.settingsMigrated++;
|
result.settingsMigrated++;
|
||||||
@@ -1094,12 +1138,19 @@ export async function migrateSettings(): Promise<MigrationResult> {
|
|||||||
|
|
||||||
// Wait for all migrations to complete
|
// Wait for all migrations to complete
|
||||||
const updatedSettings = await Promise.all(migrationPromises);
|
const updatedSettings = await Promise.all(migrationPromises);
|
||||||
|
|
||||||
logger.info("[MigrationService] Finished migrating settings", updatedSettings, result);
|
logger.info(
|
||||||
|
"[MigrationService] Finished migrating settings",
|
||||||
|
updatedSettings,
|
||||||
|
result,
|
||||||
|
);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error("[MigrationService] Complete settings migration failed:", error);
|
logger.error(
|
||||||
|
"[MigrationService] Complete settings migration failed:",
|
||||||
|
error,
|
||||||
|
);
|
||||||
const errorMessage = `Settings migration failed: ${error}`;
|
const errorMessage = `Settings migration failed: ${error}`;
|
||||||
result.errors.push(errorMessage);
|
result.errors.push(errorMessage);
|
||||||
result.success = false;
|
result.success = false;
|
||||||
@@ -1158,12 +1209,17 @@ export async function migrateAccounts(): Promise<MigrationResult> {
|
|||||||
|
|
||||||
// Group accounts by DID and keep only the most recent one
|
// Group accounts by DID and keep only the most recent one
|
||||||
const accountsByDid = new Map<string, Account>();
|
const accountsByDid = new Map<string, Account>();
|
||||||
dexieAccounts.forEach(account => {
|
dexieAccounts.forEach((account) => {
|
||||||
const existingAccount = accountsByDid.get(account.did);
|
const existingAccount = accountsByDid.get(account.did);
|
||||||
if (!existingAccount || new Date(account.dateCreated) > new Date(existingAccount.dateCreated)) {
|
if (
|
||||||
|
!existingAccount ||
|
||||||
|
new Date(account.dateCreated) > new Date(existingAccount.dateCreated)
|
||||||
|
) {
|
||||||
accountsByDid.set(account.did, account);
|
accountsByDid.set(account.did, account);
|
||||||
if (existingAccount) {
|
if (existingAccount) {
|
||||||
result.warnings.push(`Found duplicate account for DID ${account.did}, keeping most recent`);
|
result.warnings.push(
|
||||||
|
`Found duplicate account for DID ${account.did}, keeping most recent`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -1174,30 +1230,34 @@ export async function migrateAccounts(): Promise<MigrationResult> {
|
|||||||
// Check if account already exists
|
// Check if account already exists
|
||||||
const existingResult = await platformService.dbQuery(
|
const existingResult = await platformService.dbQuery(
|
||||||
"SELECT did FROM accounts WHERE did = ?",
|
"SELECT did FROM accounts WHERE did = ?",
|
||||||
[did]
|
[did],
|
||||||
);
|
);
|
||||||
|
|
||||||
if (existingResult?.values?.length) {
|
if (existingResult?.values?.length) {
|
||||||
result.warnings.push(`Account with DID ${did} already exists, skipping`);
|
result.warnings.push(
|
||||||
|
`Account with DID ${did} already exists, skipping`,
|
||||||
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (account.mnemonic) {
|
if (account.mnemonic) {
|
||||||
await importFromMnemonic(account.mnemonic, account.derivationPath);
|
await importFromMnemonic(account.mnemonic, account.derivationPath);
|
||||||
result.accountsMigrated++;
|
result.accountsMigrated++;
|
||||||
} else {
|
} else {
|
||||||
result.errors.push(`Account with DID ${did} has no mnemonic, skipping`);
|
result.errors.push(
|
||||||
|
`Account with DID ${did} has no mnemonic, skipping`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info("[MigrationService] Successfully migrated account", {
|
logger.info("[MigrationService] Successfully migrated account", {
|
||||||
did,
|
did,
|
||||||
dateCreated: account.dateCreated
|
dateCreated: account.dateCreated,
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const errorMessage = `Failed to migrate account ${did}: ${error}`;
|
const errorMessage = `Failed to migrate account ${did}: ${error}`;
|
||||||
result.errors.push(errorMessage);
|
result.errors.push(errorMessage);
|
||||||
logger.error("[MigrationService] Account migration failed:", {
|
logger.error("[MigrationService] Account migration failed:", {
|
||||||
error,
|
error,
|
||||||
did
|
did,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1211,7 +1271,10 @@ export async function migrateAccounts(): Promise<MigrationResult> {
|
|||||||
const errorMessage = `Account migration failed: ${error}`;
|
const errorMessage = `Account migration failed: ${error}`;
|
||||||
result.errors.push(errorMessage);
|
result.errors.push(errorMessage);
|
||||||
result.success = false;
|
result.success = false;
|
||||||
logger.error("[MigrationService] Complete account migration failed:", error);
|
logger.error(
|
||||||
|
"[MigrationService] Complete account migration failed:",
|
||||||
|
error,
|
||||||
|
);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,8 +9,9 @@
|
|||||||
databases
|
databases
|
||||||
</p>
|
</p>
|
||||||
<p class="mt-2 text-gray-600">
|
<p class="mt-2 text-gray-600">
|
||||||
First, we recommend you hit these first two buttons to get your backups, just in case!
|
First, we recommend you hit these first two buttons to get your
|
||||||
If anything doesn't look right when you're done, Trent will help with... anything and everything. 😁
|
backups, just in case! If anything doesn't look right when you're
|
||||||
|
done, Trent will help with... anything and everything. 😁
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -50,28 +51,34 @@
|
|||||||
</div>
|
</div>
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<div
|
<div class="text-lg leading-6 font-medium text-red-900 mt-4">
|
||||||
class="text-lg leading-6 font-medium text-red-900 mt-4"
|
|
||||||
>
|
|
||||||
<p
|
<p
|
||||||
v-if="comparison && (comparison.sqliteAccounts.length > 1 || comparison.sqliteSettings.length > 1 || comparison.sqliteContacts.length > 0)"
|
v-if="
|
||||||
|
comparison &&
|
||||||
|
(comparison.sqliteAccounts.length > 1 ||
|
||||||
|
comparison.sqliteSettings.length > 1 ||
|
||||||
|
comparison.sqliteContacts.length > 0)
|
||||||
|
"
|
||||||
>
|
>
|
||||||
Beware: you have unexpected existing data in the new database that will be overwritten. Talk with Trent.
|
Beware: you have unexpected existing data in the new database that
|
||||||
|
will be overwritten. Talk with Trent.
|
||||||
</p>
|
</p>
|
||||||
<p
|
<p v-if="cannotfindMainAccount">
|
||||||
v-if="cannotfindMainAccount"
|
|
||||||
>
|
|
||||||
We cannot find your main account. Talk with Trent.
|
We cannot find your main account. Talk with Trent.
|
||||||
</p>
|
</p>
|
||||||
<p
|
<p v-if="hasMultipleMnemonics">
|
||||||
v-if="hasMultipleMnemonics"
|
|
||||||
>
|
|
||||||
You have multiple accounts. If you didn't mean to, talk with Trent.
|
You have multiple accounts. If you didn't mean to, talk with Trent.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p v-if="downloadMnemonic" class="text-green-500">
|
<p v-if="downloadMnemonic" class="text-green-500">
|
||||||
Here is your seed for account {{ downloadMnemonicAddress?.substring('did:ethr:0x'.length).substring(0, 3) }} -- write it down!
|
Here is your seed for account
|
||||||
|
{{
|
||||||
|
downloadMnemonicAddress
|
||||||
|
?.substring("did:ethr:0x".length)
|
||||||
|
.substring(0, 3)
|
||||||
|
}}
|
||||||
|
-- write it down!
|
||||||
<br />
|
<br />
|
||||||
{{ downloadMnemonic }}
|
{{ downloadMnemonic }}
|
||||||
</p>
|
</p>
|
||||||
@@ -533,9 +540,7 @@
|
|||||||
icon-name="trash"
|
icon-name="trash"
|
||||||
svg-class="h-5 w-5 text-red-600 mr-2"
|
svg-class="h-5 w-5 text-red-600 mr-2"
|
||||||
/>
|
/>
|
||||||
<span class="text-sm font-medium text-red-900"
|
<span class="text-sm font-medium text-red-900">Keep</span>
|
||||||
>Keep</span
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
<span class="text-sm font-bold text-red-900">{{
|
<span class="text-sm font-bold text-red-900">{{
|
||||||
comparison.differences.accounts.missing.length
|
comparison.differences.accounts.missing.length
|
||||||
@@ -549,7 +554,9 @@
|
|||||||
class="mt-4"
|
class="mt-4"
|
||||||
>
|
>
|
||||||
<h4 class="text-sm font-medium text-gray-900 mb-2">
|
<h4 class="text-sm font-medium text-gray-900 mb-2">
|
||||||
Add Accounts ({{ comparison.differences.accounts.added.length }}):
|
Add Accounts ({{
|
||||||
|
comparison.differences.accounts.added.length
|
||||||
|
}}):
|
||||||
</h4>
|
</h4>
|
||||||
<div class="space-y-1">
|
<div class="space-y-1">
|
||||||
<div
|
<div
|
||||||
@@ -559,9 +566,17 @@
|
|||||||
>
|
>
|
||||||
<div class="font-medium">ID: {{ account.id }}</div>
|
<div class="font-medium">ID: {{ account.id }}</div>
|
||||||
<div class="text-gray-500">{{ account.did }}</div>
|
<div class="text-gray-500">{{ account.did }}</div>
|
||||||
<div class="text-gray-400">Created: {{ account.dateCreated }}</div>
|
<div class="text-gray-400">
|
||||||
<div class="text-gray-400">Has Identity: {{ getAccountHasIdentity(account) ? 'Yes' : 'No' }}</div>
|
Created: {{ account.dateCreated }}
|
||||||
<div class="text-gray-400">Has Mnemonic: {{ getAccountHasMnemonic(account) ? 'Yes' : 'No' }}</div>
|
</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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -572,7 +587,9 @@
|
|||||||
class="mt-4"
|
class="mt-4"
|
||||||
>
|
>
|
||||||
<h4 class="text-sm font-medium text-gray-900 mb-2">
|
<h4 class="text-sm font-medium text-gray-900 mb-2">
|
||||||
Unmodified Accounts ({{ comparison.differences.accounts.unmodified.length }}):
|
Unmodified Accounts ({{
|
||||||
|
comparison.differences.accounts.unmodified.length
|
||||||
|
}}):
|
||||||
</h4>
|
</h4>
|
||||||
</div>
|
</div>
|
||||||
<div class="space-y-1">
|
<div class="space-y-1">
|
||||||
@@ -583,23 +600,39 @@
|
|||||||
>
|
>
|
||||||
<div class="font-medium">ID: {{ account.id }}</div>
|
<div class="font-medium">ID: {{ account.id }}</div>
|
||||||
<div class="text-gray-500">{{ account.did }}</div>
|
<div class="text-gray-500">{{ account.did }}</div>
|
||||||
<div class="text-gray-400">Created: {{ account.dateCreated }}</div>
|
<div class="text-gray-400">
|
||||||
<div class="text-gray-400">Has Identity: {{ getAccountHasIdentity(account) ? 'Yes' : 'No' }}</div>
|
Created: {{ account.dateCreated }}
|
||||||
<div class="text-gray-400">Has Mnemonic: {{ getAccountHasMnemonic(account) ? 'Yes' : 'No' }}</div>
|
</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>
|
</div>
|
||||||
|
|
||||||
<!-- Keep Accounts -->
|
<!-- Keep Accounts -->
|
||||||
<div
|
<div
|
||||||
v-if="comparison.differences.accounts.missing.filter(a => a).length > 0"
|
v-if="
|
||||||
|
comparison.differences.accounts.missing.filter((a) => a)
|
||||||
|
.length > 0
|
||||||
|
"
|
||||||
class="mt-4"
|
class="mt-4"
|
||||||
>
|
>
|
||||||
<h4 class="text-sm font-medium text-gray-900 mb-2">
|
<h4 class="text-sm font-medium text-gray-900 mb-2">
|
||||||
Keep Accounts ({{ comparison.differences.accounts.missing.filter(a => a).length }}):
|
Keep Accounts ({{
|
||||||
|
comparison.differences.accounts.missing.filter((a) => a)
|
||||||
|
.length
|
||||||
|
}}):
|
||||||
</h4>
|
</h4>
|
||||||
<div class="space-y-1">
|
<div class="space-y-1">
|
||||||
<div
|
<div
|
||||||
v-for="did in comparison.differences.accounts.missing.filter(a => a)"
|
v-for="did in comparison.differences.accounts.missing.filter(
|
||||||
|
(a) => a,
|
||||||
|
)"
|
||||||
:key="did"
|
:key="did"
|
||||||
class="text-xs text-gray-600 bg-gray-50 p-2 rounded"
|
class="text-xs text-gray-600 bg-gray-50 p-2 rounded"
|
||||||
>
|
>
|
||||||
@@ -675,9 +708,7 @@
|
|||||||
icon-name="trash"
|
icon-name="trash"
|
||||||
svg-class="h-5 w-5 text-red-600 mr-2"
|
svg-class="h-5 w-5 text-red-600 mr-2"
|
||||||
/>
|
/>
|
||||||
<span class="text-sm font-medium text-red-900"
|
<span class="text-sm font-medium text-red-900">Keep</span>
|
||||||
>Keep</span
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
<span class="text-sm font-bold text-red-900">{{
|
<span class="text-sm font-bold text-red-900">{{
|
||||||
comparison.differences.settings.missing.length
|
comparison.differences.settings.missing.length
|
||||||
@@ -691,7 +722,9 @@
|
|||||||
class="mt-4"
|
class="mt-4"
|
||||||
>
|
>
|
||||||
<h4 class="text-sm font-medium text-gray-900 mb-2">
|
<h4 class="text-sm font-medium text-gray-900 mb-2">
|
||||||
Add Settings ({{ comparison.differences.settings.added.length }}):
|
Add Settings ({{
|
||||||
|
comparison.differences.settings.added.length
|
||||||
|
}}):
|
||||||
</h4>
|
</h4>
|
||||||
<div class="space-y-1">
|
<div class="space-y-1">
|
||||||
<div
|
<div
|
||||||
@@ -699,9 +732,13 @@
|
|||||||
:key="setting.id"
|
:key="setting.id"
|
||||||
class="text-xs text-gray-600 bg-gray-50 p-2 rounded"
|
class="text-xs text-gray-600 bg-gray-50 p-2 rounded"
|
||||||
>
|
>
|
||||||
<div class="font-medium">{{ getSettingDisplayName(setting) }}</div>
|
<div class="font-medium">
|
||||||
|
{{ getSettingDisplayName(setting) }}
|
||||||
|
</div>
|
||||||
<div class="text-gray-500">ID: {{ setting.id }}</div>
|
<div class="text-gray-500">ID: {{ setting.id }}</div>
|
||||||
<div class="text-gray-400">Registered: {{ setting.isRegistered ? 'Yes' : 'No' }}</div>
|
<div class="text-gray-400">
|
||||||
|
Registered: {{ setting.isRegistered ? "Yes" : "No" }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -712,7 +749,9 @@
|
|||||||
class="mt-4"
|
class="mt-4"
|
||||||
>
|
>
|
||||||
<h4 class="text-sm font-medium text-gray-900 mb-2">
|
<h4 class="text-sm font-medium text-gray-900 mb-2">
|
||||||
Modify Settings ({{ comparison.differences.settings.modified.length }}):
|
Modify Settings ({{
|
||||||
|
comparison.differences.settings.modified.length
|
||||||
|
}}):
|
||||||
</h4>
|
</h4>
|
||||||
<div class="space-y-1">
|
<div class="space-y-1">
|
||||||
<div
|
<div
|
||||||
@@ -720,9 +759,13 @@
|
|||||||
:key="setting.id"
|
:key="setting.id"
|
||||||
class="text-xs text-gray-600 bg-gray-50 p-2 rounded"
|
class="text-xs text-gray-600 bg-gray-50 p-2 rounded"
|
||||||
>
|
>
|
||||||
<div class="font-medium">{{ getSettingDisplayName(setting) }}</div>
|
<div class="font-medium">
|
||||||
|
{{ getSettingDisplayName(setting) }}
|
||||||
|
</div>
|
||||||
<div class="text-gray-500">ID: {{ setting.id }}</div>
|
<div class="text-gray-500">ID: {{ setting.id }}</div>
|
||||||
<div class="text-gray-400">Registered: {{ setting.isRegistered ? 'Yes' : 'No' }}</div>
|
<div class="text-gray-400">
|
||||||
|
Registered: {{ setting.isRegistered ? "Yes" : "No" }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -733,7 +776,9 @@
|
|||||||
class="mt-4"
|
class="mt-4"
|
||||||
>
|
>
|
||||||
<h4 class="text-sm font-medium text-gray-900 mb-2">
|
<h4 class="text-sm font-medium text-gray-900 mb-2">
|
||||||
Unmodified Settings ({{ comparison.differences.settings.unmodified.length }}):
|
Unmodified Settings ({{
|
||||||
|
comparison.differences.settings.unmodified.length
|
||||||
|
}}):
|
||||||
</h4>
|
</h4>
|
||||||
</div>
|
</div>
|
||||||
<div class="space-y-1">
|
<div class="space-y-1">
|
||||||
@@ -742,29 +787,47 @@
|
|||||||
:key="setting.id"
|
:key="setting.id"
|
||||||
class="text-xs text-gray-600 bg-gray-50 p-2 rounded"
|
class="text-xs text-gray-600 bg-gray-50 p-2 rounded"
|
||||||
>
|
>
|
||||||
<div class="font-medium">{{ getSettingDisplayName(setting) }}</div>
|
<div class="font-medium">
|
||||||
|
{{ getSettingDisplayName(setting) }}
|
||||||
|
</div>
|
||||||
<div class="text-gray-500">ID: {{ setting.id }}</div>
|
<div class="text-gray-500">ID: {{ setting.id }}</div>
|
||||||
<div class="text-gray-400">Registered: {{ setting.isRegistered ? 'Yes' : 'No' }}</div>
|
<div class="text-gray-400">
|
||||||
|
Registered: {{ setting.isRegistered ? "Yes" : "No" }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Keep Settings -->
|
<!-- Keep Settings -->
|
||||||
<div
|
<div
|
||||||
v-if="comparison.differences.settings.missing.filter(s => s.accountDid || s.activeDid).length > 0"
|
v-if="
|
||||||
|
comparison.differences.settings.missing.filter(
|
||||||
|
(s) => s.accountDid || s.activeDid,
|
||||||
|
).length > 0
|
||||||
|
"
|
||||||
class="mt-4"
|
class="mt-4"
|
||||||
>
|
>
|
||||||
<h4 class="text-sm font-medium text-gray-900 mb-2">
|
<h4 class="text-sm font-medium text-gray-900 mb-2">
|
||||||
Keep Settings ({{ comparison.differences.settings.missing.filter(s => s.accountDid || s.activeDid).length }}):
|
Keep Settings ({{
|
||||||
|
comparison.differences.settings.missing.filter(
|
||||||
|
(s) => s.accountDid || s.activeDid,
|
||||||
|
).length
|
||||||
|
}}):
|
||||||
</h4>
|
</h4>
|
||||||
<div class="space-y-1">
|
<div class="space-y-1">
|
||||||
<div
|
<div
|
||||||
v-for="setting in comparison.differences.settings.missing.filter(s => s.accountDid || s.activeDid)"
|
v-for="setting in comparison.differences.settings.missing.filter(
|
||||||
|
(s) => s.accountDid || s.activeDid,
|
||||||
|
)"
|
||||||
:key="setting.id"
|
:key="setting.id"
|
||||||
class="text-xs text-gray-600 bg-gray-50 p-2 rounded"
|
class="text-xs text-gray-600 bg-gray-50 p-2 rounded"
|
||||||
>
|
>
|
||||||
<div class="font-medium">{{ getSettingDisplayName(setting) }}</div>
|
<div class="font-medium">
|
||||||
|
{{ getSettingDisplayName(setting) }}
|
||||||
|
</div>
|
||||||
<div class="text-gray-500">ID: {{ setting.id }}</div>
|
<div class="text-gray-500">ID: {{ setting.id }}</div>
|
||||||
<div class="text-gray-400">Registered: {{ setting.isRegistered ? 'Yes' : 'No' }}</div>
|
<div class="text-gray-400">
|
||||||
|
Registered: {{ setting.isRegistered ? "Yes" : "No" }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -836,9 +899,7 @@
|
|||||||
icon-name="trash"
|
icon-name="trash"
|
||||||
svg-class="h-5 w-5 text-red-600 mr-2"
|
svg-class="h-5 w-5 text-red-600 mr-2"
|
||||||
/>
|
/>
|
||||||
<span class="text-sm font-medium text-red-900"
|
<span class="text-sm font-medium text-red-900">Keep</span>
|
||||||
>Keep</span
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
<span class="text-sm font-bold text-red-900">{{
|
<span class="text-sm font-bold text-red-900">{{
|
||||||
comparison.differences.contacts.missing.length
|
comparison.differences.contacts.missing.length
|
||||||
@@ -852,7 +913,9 @@
|
|||||||
class="mt-4"
|
class="mt-4"
|
||||||
>
|
>
|
||||||
<h4 class="text-sm font-medium text-gray-900 mb-2">
|
<h4 class="text-sm font-medium text-gray-900 mb-2">
|
||||||
Add Contacts ({{ comparison.differences.contacts.added.length }}):
|
Add Contacts ({{
|
||||||
|
comparison.differences.contacts.added.length
|
||||||
|
}}):
|
||||||
</h4>
|
</h4>
|
||||||
<div class="space-y-1">
|
<div class="space-y-1">
|
||||||
<div
|
<div
|
||||||
@@ -860,9 +923,13 @@
|
|||||||
:key="contact.did"
|
:key="contact.did"
|
||||||
class="text-xs text-gray-600 bg-gray-50 p-2 rounded"
|
class="text-xs text-gray-600 bg-gray-50 p-2 rounded"
|
||||||
>
|
>
|
||||||
<div class="font-medium">{{ contact.name || '<empty>' }}</div>
|
<div class="font-medium">
|
||||||
|
{{ contact.name || "(empty)" }}
|
||||||
|
</div>
|
||||||
<div class="text-gray-500">{{ contact.did }}</div>
|
<div class="text-gray-500">{{ contact.did }}</div>
|
||||||
<div class="text-gray-400">{{ contact.contactMethods?.length || 0 }} contact methods</div>
|
<div class="text-gray-400">
|
||||||
|
{{ contact.contactMethods?.length || 0 }} contact methods
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -873,7 +940,9 @@
|
|||||||
class="mt-4"
|
class="mt-4"
|
||||||
>
|
>
|
||||||
<h4 class="text-sm font-medium text-gray-900 mb-2">
|
<h4 class="text-sm font-medium text-gray-900 mb-2">
|
||||||
Modify Contacts ({{ comparison.differences.contacts.modified.length }}):
|
Modify Contacts ({{
|
||||||
|
comparison.differences.contacts.modified.length
|
||||||
|
}}):
|
||||||
</h4>
|
</h4>
|
||||||
<div class="space-y-1">
|
<div class="space-y-1">
|
||||||
<div
|
<div
|
||||||
@@ -881,9 +950,13 @@
|
|||||||
:key="contact.did"
|
:key="contact.did"
|
||||||
class="text-xs text-gray-600 bg-gray-50 p-2 rounded"
|
class="text-xs text-gray-600 bg-gray-50 p-2 rounded"
|
||||||
>
|
>
|
||||||
<div class="font-medium">{{ contact.name || '<empty>' }}</div>
|
<div class="font-medium">
|
||||||
|
{{ contact.name || "(empty)" }}
|
||||||
|
</div>
|
||||||
<div class="text-gray-500">{{ contact.did }}</div>
|
<div class="text-gray-500">{{ contact.did }}</div>
|
||||||
<div class="text-gray-400">{{ contact.contactMethods?.length || 0 }} contact methods</div>
|
<div class="text-gray-400">
|
||||||
|
{{ contact.contactMethods?.length || 0 }} contact methods
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -894,7 +967,9 @@
|
|||||||
class="mt-4"
|
class="mt-4"
|
||||||
>
|
>
|
||||||
<h4 class="text-sm font-medium text-gray-900 mb-2">
|
<h4 class="text-sm font-medium text-gray-900 mb-2">
|
||||||
Unmodified Contacts ({{ comparison.differences.contacts.unmodified.length }}):
|
Unmodified Contacts ({{
|
||||||
|
comparison.differences.contacts.unmodified.length
|
||||||
|
}}):
|
||||||
</h4>
|
</h4>
|
||||||
</div>
|
</div>
|
||||||
<div class="space-y-1">
|
<div class="space-y-1">
|
||||||
@@ -903,29 +978,45 @@
|
|||||||
:key="contact.did"
|
:key="contact.did"
|
||||||
class="text-xs text-gray-600 bg-gray-50 p-2 rounded"
|
class="text-xs text-gray-600 bg-gray-50 p-2 rounded"
|
||||||
>
|
>
|
||||||
<div class="font-medium">{{ contact.name || '<empty>' }}</div>
|
<div class="font-medium">
|
||||||
|
{{ contact.name || "(empty)" }}
|
||||||
|
</div>
|
||||||
<div class="text-gray-500">{{ contact.did }}</div>
|
<div class="text-gray-500">{{ contact.did }}</div>
|
||||||
<div class="text-gray-400">{{ contact.contactMethods?.length || 0 }} contact methods</div>
|
<div class="text-gray-400">
|
||||||
|
{{ contact.contactMethods?.length || 0 }} contact methods
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Keep Contacts -->
|
<!-- Keep Contacts -->
|
||||||
<div
|
<div
|
||||||
v-if="comparison.differences.contacts.missing.filter(c => c.did).length > 0"
|
v-if="
|
||||||
|
comparison.differences.contacts.missing.filter((c) => c.did)
|
||||||
|
.length > 0
|
||||||
|
"
|
||||||
class="mt-4"
|
class="mt-4"
|
||||||
>
|
>
|
||||||
<h4 class="text-sm font-medium text-gray-900 mb-2">
|
<h4 class="text-sm font-medium text-gray-900 mb-2">
|
||||||
Keep Contacts ({{ comparison.differences.contacts.missing.filter(c => c.did).length }}):
|
Keep Contacts ({{
|
||||||
|
comparison.differences.contacts.missing.filter((c) => c.did)
|
||||||
|
.length
|
||||||
|
}}):
|
||||||
</h4>
|
</h4>
|
||||||
<div class="space-y-1">
|
<div class="space-y-1">
|
||||||
<div
|
<div
|
||||||
v-for="contact in comparison.differences.contacts.missing.filter(c => c.did)"
|
v-for="contact in comparison.differences.contacts.missing.filter(
|
||||||
|
(c) => c.did,
|
||||||
|
)"
|
||||||
:key="contact.did"
|
:key="contact.did"
|
||||||
class="text-xs text-gray-600 bg-gray-50 p-2 rounded"
|
class="text-xs text-gray-600 bg-gray-50 p-2 rounded"
|
||||||
>
|
>
|
||||||
<div class="font-medium">{{ contact.name || '<empty>' }}</div>
|
<div class="font-medium">
|
||||||
|
{{ contact.name || "(empty)" }}
|
||||||
|
</div>
|
||||||
<div class="text-gray-500">{{ contact.did }}</div>
|
<div class="text-gray-500">{{ contact.did }}</div>
|
||||||
<div class="text-gray-400">{{ contact.contactMethods?.length || 0 }} contact methods</div>
|
<div class="text-gray-400">
|
||||||
|
{{ contact.contactMethods?.length || 0 }} contact methods
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -939,8 +1030,8 @@
|
|||||||
<div v-if="exportedData" class="mt-4 space-y-6">
|
<div v-if="exportedData" class="mt-4 space-y-6">
|
||||||
<h2>Exported Data</h2>
|
<h2>Exported Data</h2>
|
||||||
<span
|
<span
|
||||||
v-on:click="copyToClipboard"
|
|
||||||
class="text-blue-500 cursor-pointer hover:text-blue-700"
|
class="text-blue-500 cursor-pointer hover:text-blue-700"
|
||||||
|
@click="copyToClipboard"
|
||||||
>
|
>
|
||||||
Copy to Clipboard
|
Copy to Clipboard
|
||||||
</span>
|
</span>
|
||||||
@@ -1025,11 +1116,11 @@ export default class DatabaseMigration extends Vue {
|
|||||||
if (setting.type && setting.did) {
|
if (setting.type && setting.did) {
|
||||||
return `${setting.type} (${setting.did})`;
|
return `${setting.type} (${setting.did})`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle live comparison data (has 'activeDid' or 'accountDid' fields)
|
// Handle live comparison data (has 'activeDid' or 'accountDid' fields)
|
||||||
const did = setting.activeDid || setting.accountDid;
|
const did = setting.activeDid || setting.accountDid;
|
||||||
const type = setting.id === 1 ? 'master' : 'account';
|
const type = setting.id === 1 ? "master" : "account";
|
||||||
return `${type} (${did || 'no DID'})`;
|
return `${type} (${did || "no DID"})`;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1044,7 +1135,7 @@ export default class DatabaseMigration extends Vue {
|
|||||||
if (account.hasIdentity !== undefined) {
|
if (account.hasIdentity !== undefined) {
|
||||||
return account.hasIdentity;
|
return account.hasIdentity;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle live comparison data (has 'identity' field)
|
// Handle live comparison data (has 'identity' field)
|
||||||
return !!account.identity;
|
return !!account.identity;
|
||||||
}
|
}
|
||||||
@@ -1061,7 +1152,7 @@ export default class DatabaseMigration extends Vue {
|
|||||||
if (account.hasMnemonic !== undefined) {
|
if (account.hasMnemonic !== undefined) {
|
||||||
return account.hasMnemonic;
|
return account.hasMnemonic;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle live comparison data (has 'mnemonic' field)
|
// Handle live comparison data (has 'mnemonic' field)
|
||||||
return !!account.mnemonic;
|
return !!account.mnemonic;
|
||||||
}
|
}
|
||||||
@@ -1071,17 +1162,19 @@ export default class DatabaseMigration extends Vue {
|
|||||||
*/
|
*/
|
||||||
async copyToClipboard(): Promise<void> {
|
async copyToClipboard(): Promise<void> {
|
||||||
if (!this.exportedData) return;
|
if (!this.exportedData) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await this.useClipboard().copy(JSON.stringify(this.exportedData, null, 2));
|
await this.useClipboard().copy(
|
||||||
|
JSON.stringify(this.exportedData, null, 2),
|
||||||
|
);
|
||||||
// Use global window object properly
|
// Use global window object properly
|
||||||
if (typeof window !== 'undefined') {
|
if (typeof window !== "undefined") {
|
||||||
window.alert('Copied to clipboard!');
|
window.alert("Copied to clipboard!");
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error('Failed to copy to clipboard:', error);
|
logger.error("Failed to copy to clipboard:", error);
|
||||||
if (typeof window !== 'undefined') {
|
if (typeof window !== "undefined") {
|
||||||
window.alert('Failed to copy to clipboard');
|
window.alert("Failed to copy to clipboard");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1093,7 +1186,7 @@ export default class DatabaseMigration extends Vue {
|
|||||||
let primaryAccount;
|
let primaryAccount;
|
||||||
if (settings.length > 0) {
|
if (settings.length > 0) {
|
||||||
const primaryDid = settings[0].activeDid;
|
const primaryDid = settings[0].activeDid;
|
||||||
primaryAccount = accounts.find(acc => acc.did === primaryDid);
|
primaryAccount = accounts.find((acc) => acc.did === primaryDid);
|
||||||
if (!primaryAccount) {
|
if (!primaryAccount) {
|
||||||
this.cannotfindMainAccount = true;
|
this.cannotfindMainAccount = true;
|
||||||
// abort everything
|
// abort everything
|
||||||
@@ -1121,7 +1214,7 @@ export default class DatabaseMigration extends Vue {
|
|||||||
this.exportedData = {
|
this.exportedData = {
|
||||||
accounts: await getDexieAccounts(),
|
accounts: await getDexieAccounts(),
|
||||||
settings: await getDexieSettings(),
|
settings: await getDexieSettings(),
|
||||||
contacts: await getDexieContacts()
|
contacts: await getDexieContacts(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1334,15 +1427,15 @@ export default class DatabaseMigration extends Vue {
|
|||||||
const yamlData = generateComparisonYaml(this.comparison);
|
const yamlData = generateComparisonYaml(this.comparison);
|
||||||
const blob = new Blob([yamlData], { type: "application/json" });
|
const blob = new Blob([yamlData], { type: "application/json" });
|
||||||
const url = URL.createObjectURL(blob);
|
const url = URL.createObjectURL(blob);
|
||||||
|
|
||||||
const a = document.createElement("a");
|
const a = document.createElement("a");
|
||||||
a.href = url;
|
a.href = url;
|
||||||
a.download = `database-comparison-${new Date().toISOString().split('T')[0]}.json`;
|
a.download = `database-comparison-${new Date().toISOString().split("T")[0]}.json`;
|
||||||
document.body.appendChild(a);
|
document.body.appendChild(a);
|
||||||
a.click();
|
a.click();
|
||||||
document.body.removeChild(a);
|
document.body.removeChild(a);
|
||||||
URL.revokeObjectURL(url);
|
URL.revokeObjectURL(url);
|
||||||
|
|
||||||
this.successMessage = "Comparison data exported successfully";
|
this.successMessage = "Comparison data exported successfully";
|
||||||
logger.info("[DatabaseMigration] Comparison data exported successfully");
|
logger.info("[DatabaseMigration] Comparison data exported successfully");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
Reference in New Issue
Block a user