Merge branch 'sql-absurd-sql-back'

This commit is contained in:
2025-06-07 17:18:10 -06:00
147 changed files with 10865 additions and 3762 deletions

View File

@@ -175,117 +175,119 @@
data-testId="contactListItem"
>
<div class="grow overflow-hidden">
<div class="flex items-center gap-3">
<input
v-if="!showGiveNumbers"
type="checkbox"
:checked="contactsSelected.includes(contact.did)"
class="ml-2 h-6 w-6 flex-shrink-0"
data-testId="contactCheckOne"
@click="
contactsSelected.includes(contact.did)
? contactsSelected.splice(
contactsSelected.indexOf(contact.did),
1,
)
: contactsSelected.push(contact.did)
"
/>
<div class="flex items-center justify-between gap-3">
<div class="flex items-center gap-3">
<input
v-if="!showGiveNumbers"
type="checkbox"
:checked="contactsSelected.includes(contact.did)"
class="ml-2 h-6 w-6 flex-shrink-0"
data-testId="contactCheckOne"
@click="
contactsSelected.includes(contact.did)
? contactsSelected.splice(
contactsSelected.indexOf(contact.did),
1,
)
: contactsSelected.push(contact.did)
"
/>
<EntityIcon
:contact="contact"
:icon-size="48"
class="inline-block align-text-bottom border border-slate-300 rounded cursor-pointer overflow-hidden"
@click="showLargeIdenticon = contact"
/>
<h2 class="text-base font-semibold w-1/3 truncate flex-shrink-0">
{{ contactNameNonBreakingSpace(contact.name) }}
</h2>
<span>
<div class="flex gap-2 items-center">
<router-link
:to="{
path: '/did/' + encodeURIComponent(contact.did),
}"
title="See more about this person"
>
<font-awesome
icon="circle-info"
class="text-xl text-blue-500"
/>
</router-link>
<span class="text-sm overflow-hidden">{{
libsUtil.shortDid(contact.did)
}}</span>
<div class="flex-shrink-0 w-12 h-12 flex items-center justify-center">
<EntityIcon
:contact="contact"
:icon-size="48"
class="inline-block align-text-bottom border border-slate-300 rounded cursor-pointer overflow-hidden"
@click="showLargeIdenticon = contact"
/>
</div>
<div class="text-sm">
{{ contact.notes }}
</div>
</span>
</div>
<div
v-if="showGiveNumbers && contact.did != activeDid"
class="ml-auto flex gap-1.5 mt-2"
>
<button
class="text-sm bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-2 py-1.5 rounded-l-md"
:title="givenToMeDescriptions[contact.did] || ''"
@click="confirmShowGiftedDialog(contact.did, activeDid)"
>
From:
<br />
{{
/* eslint-disable prettier/prettier */
showGiveTotals
? ((givenToMeConfirmed[contact.did] || 0)
+ (givenToMeUnconfirmed[contact.did] || 0))
: showGiveConfirmed
? (givenToMeConfirmed[contact.did] || 0)
: (givenToMeUnconfirmed[contact.did] || 0)
/* eslint-enable prettier/prettier */
}}
</button>
<button
class="text-sm bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white -ml-1.5 px-2 py-1.5 rounded-r-md border-l"
:title="givenByMeDescriptions[contact.did] || ''"
@click="confirmShowGiftedDialog(activeDid, contact.did)"
>
To:
<br />
{{
/* eslint-disable prettier/prettier */
showGiveTotals
? ((givenByMeConfirmed[contact.did] || 0)
+ (givenByMeUnconfirmed[contact.did] || 0))
: showGiveConfirmed
? (givenByMeConfirmed[contact.did] || 0)
: (givenByMeUnconfirmed[contact.did] || 0)
/* eslint-enable prettier/prettier */
}}
</button>
<h2 class="text-base font-semibold w-1/3 truncate flex-shrink-0">
{{ contactNameNonBreakingSpace(contact.name) }}
</h2>
<button
class="text-sm bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-2 py-1.5 rounded-md border border-blue-400"
data-testId="offerButton"
@click="openOfferDialog(contact.did, contact.name)"
>
Offer
</button>
<span>
<div class="flex gap-2 items-center">
<router-link
:to="{
path: '/did/' + encodeURIComponent(contact.did),
}"
title="See more about this person"
>
<font-awesome
icon="circle-info"
class="text-xl text-blue-500"
/>
</router-link>
<router-link
:to="{
name: 'contact-amounts',
query: { contactDid: contact.did },
}"
class="text-sm bg-gradient-to-b from-slate-400 to-slate-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-2 py-1.5 rounded-md border border-slate-400"
title="See more given activity"
>
<font-awesome icon="file-lines" class="fa-fw" />
</router-link>
<span class="text-sm overflow-hidden">{{
libsUtil.shortDid(contact.did)
}}</span>
</div>
<div class="text-sm">
{{ contact.notes }}
</div>
</span>
</div>
<div v-if="showGiveNumbers && contact.did != activeDid" class="flex gap-2 items-center">
<button
class="text-sm bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-2 py-1.5 rounded-l-md"
:title="givenToMeDescriptions[contact.did] || ''"
@click="confirmShowGiftedDialog(contact.did, activeDid)"
>
From:
<br />
{{
/* eslint-disable prettier/prettier */
showGiveTotals
? ((givenToMeConfirmed[contact.did] || 0)
+ (givenToMeUnconfirmed[contact.did] || 0))
: showGiveConfirmed
? (givenToMeConfirmed[contact.did] || 0)
: (givenToMeUnconfirmed[contact.did] || 0)
/* eslint-enable prettier/prettier */
}}
</button>
<button
class="text-sm bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white -ml-1.5 px-2 py-1.5 rounded-r-md border-l"
:title="givenByMeDescriptions[contact.did] || ''"
@click="confirmShowGiftedDialog(activeDid, contact.did)"
>
To:
<br />
{{
/* eslint-disable prettier/prettier */
showGiveTotals
? ((givenByMeConfirmed[contact.did] || 0)
+ (givenByMeUnconfirmed[contact.did] || 0))
: showGiveConfirmed
? (givenByMeConfirmed[contact.did] || 0)
: (givenByMeUnconfirmed[contact.did] || 0)
/* eslint-enable prettier/prettier */
}}
</button>
<button
class="text-sm bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-2 py-1.5 rounded-md border border-blue-400"
data-testId="offerButton"
@click="openOfferDialog(contact.did, contact.name)"
>
Offer
</button>
<router-link
:to="{
name: 'contact-amounts',
query: { contactDid: contact.did },
}"
class="text-sm bg-gradient-to-b from-slate-400 to-slate-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-2 py-1.5 rounded-md border border-slate-400"
title="See more given activity"
>
<font-awesome icon="file-lines" class="fa-fw" />
</router-link>
</div>
</div>
</div>
</li>
@@ -356,7 +358,12 @@ import GiftedDialog from "../components/GiftedDialog.vue";
import OfferDialog from "../components/OfferDialog.vue";
import ContactNameDialog from "../components/ContactNameDialog.vue";
import TopMessage from "../components/TopMessage.vue";
import { APP_SERVER, AppString, NotificationIface } from "../constants/app";
import {
APP_SERVER,
AppString,
NotificationIface,
USE_DEXIE_DB,
} from "../constants/app";
import {
db,
logConsoleAndDb,
@@ -365,6 +372,7 @@ import {
updateDefaultSettings,
} from "../db/index";
import { Contact } from "../db/tables/contacts";
import * as databaseUtil from "../db/databaseUtil";
import { getContactJwtFromJwtUrl } from "../libs/crypto";
import { decodeEndorserJwt } from "../libs/crypto/vc";
import {
@@ -385,6 +393,7 @@ import {
import * as libsUtil from "../libs/util";
import { generateSaveAndActivateIdentity } from "../libs/util";
import { logger } from "../utils/logger";
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
@Component({
components: {
GiftedDialog,
@@ -433,8 +442,11 @@ export default class ContactsView extends Vue {
libsUtil = libsUtil;
public async created() {
await db.open();
const settings = await retrieveSettingsForActiveAccount();
let settings = await databaseUtil.retrieveSettingsForActiveAccount();
if (USE_DEXIE_DB) {
await db.open();
settings = await retrieveSettingsForActiveAccount();
}
this.activeDid = settings.activeDid || "";
this.apiServer = settings.apiServer || "";
this.isRegistered = !!settings.isRegistered;
@@ -452,12 +464,22 @@ export default class ContactsView extends Vue {
this.loadGives();
}
// .orderBy("name") wouldn't retrieve any entries with a blank name
// .toCollection.sortBy("name") didn't sort in an order I understood
const baseContacts = await db.contacts.toArray();
this.contacts = baseContacts.sort((a, b) =>
(a.name || "").localeCompare(b.name || ""),
const platformService = PlatformServiceFactory.getInstance();
const dbAllContacts = await platformService.dbQuery(
"SELECT * FROM contacts ORDER BY name",
);
this.contacts = databaseUtil.mapQueryResultToValues(
dbAllContacts,
) as unknown as Contact[];
if (USE_DEXIE_DB) {
await db.open();
// .orderBy("name") wouldn't retrieve any entries with a blank name
// .toCollection.sortBy("name") didn't sort in an order I understood
const baseContacts = await db.contacts.toArray();
this.contacts = baseContacts.sort((a, b) =>
(a.name || "").localeCompare(b.name || ""),
);
}
}
private async processContactJwt() {
@@ -514,7 +536,12 @@ export default class ContactsView extends Vue {
if (response.status != 201) {
throw { error: { response: response } };
}
await updateAccountSettings(this.activeDid, { isRegistered: true });
await databaseUtil.updateAccountSettings(this.activeDid, {
isRegistered: true,
});
if (USE_DEXIE_DB) {
await updateAccountSettings(this.activeDid, { isRegistered: true });
}
this.isRegistered = true;
this.$notify(
{
@@ -815,12 +842,22 @@ export default class ContactsView extends Vue {
this.danger("An error occurred. Some contacts may have been added.");
}
// .orderBy("name") wouldn't retrieve any entries with a blank name
// .toCollection.sortBy("name") didn't sort in an order I understood
const baseContacts = await db.contacts.toArray();
this.contacts = baseContacts.sort((a, b) =>
(a.name || "").localeCompare(b.name || ""),
const platformService = PlatformServiceFactory.getInstance();
const dbAllContacts = await platformService.dbQuery(
"SELECT * FROM contacts ORDER BY name",
);
this.contacts = databaseUtil.mapQueryResultToValues(
dbAllContacts,
) as unknown as Contact[];
if (USE_DEXIE_DB) {
await db.open();
// .orderBy("name") wouldn't retrieve any entries with a blank name
// .toCollection.sortBy("name") didn't sort in an order I understood
const baseContacts = await db.contacts.toArray();
this.contacts = baseContacts.sort((a, b) =>
(a.name || "").localeCompare(b.name || ""),
);
}
return;
}
@@ -929,7 +966,15 @@ export default class ContactsView extends Vue {
seesMe,
registered,
};
return db.contacts.add(newContact);
const platformService = PlatformServiceFactory.getInstance();
const { sql, params } = databaseUtil.generateInsertStatement(
newContact as unknown as Record<string, unknown>,
"contacts",
);
await platformService.dbExec(sql, params);
if (USE_DEXIE_DB) {
await db.contacts.add(newContact);
}
}
private async addContact(newContact: Contact) {
@@ -941,8 +986,20 @@ export default class ContactsView extends Vue {
this.danger("The DID must begin with 'did:'", "Invalid DID");
return;
}
return db.contacts
.add(newContact)
const platformService = PlatformServiceFactory.getInstance();
const { sql, params } = databaseUtil.generateInsertStatement(
newContact as unknown as Record<string, unknown>,
"contacts",
);
logger.error("sql", sql);
logger.error("params", params);
let contactPromise = platformService.dbExec(sql, params);
if (USE_DEXIE_DB) {
// @ts-expect-error since the result of this promise won't be used, and this will go away soon
contactPromise = db.contacts.add(newContact);
}
return contactPromise
.then(() => {
const allContacts = this.contacts.concat([newContact]);
this.contacts = R.sort(
@@ -970,17 +1027,27 @@ export default class ContactsView extends Vue {
text: "Do you want to register them?",
onCancel: async (stopAsking?: boolean) => {
if (stopAsking) {
await updateDefaultSettings({
await databaseUtil.updateDefaultSettings({
hideRegisterPromptOnNewContact: stopAsking,
});
if (USE_DEXIE_DB) {
await updateDefaultSettings({
hideRegisterPromptOnNewContact: stopAsking,
});
}
this.hideRegisterPromptOnNewContact = stopAsking;
}
},
onNo: async (stopAsking?: boolean) => {
if (stopAsking) {
await updateDefaultSettings({
await databaseUtil.updateDefaultSettings({
hideRegisterPromptOnNewContact: stopAsking,
});
if (USE_DEXIE_DB) {
await updateDefaultSettings({
hideRegisterPromptOnNewContact: stopAsking,
});
}
this.hideRegisterPromptOnNewContact = stopAsking;
}
},
@@ -1058,7 +1125,14 @@ export default class ContactsView extends Vue {
);
if (regResult.success) {
contact.registered = true;
await db.contacts.update(contact.did, { registered: true });
const platformService = PlatformServiceFactory.getInstance();
await platformService.dbExec(
"UPDATE contacts SET registered = ? WHERE did = ?",
[true, contact.did],
);
if (USE_DEXIE_DB) {
await db.contacts.update(contact.did, { registered: true });
}
this.$notify(
{
@@ -1267,9 +1341,14 @@ export default class ContactsView extends Vue {
private async toggleShowContactAmounts() {
const newShowValue = !this.showGiveNumbers;
try {
await updateDefaultSettings({
await databaseUtil.updateDefaultSettings({
showContactGivesInline: newShowValue,
});
if (USE_DEXIE_DB) {
await updateDefaultSettings({
showContactGivesInline: newShowValue,
});
}
} catch (err) {
const fullError =
"Error updating contact-amounts setting: " + errorStringForLog(err);