Browse Source

fix alert when looking at one's own activity

master
Trent Larson 5 days ago
parent
commit
9b86af8508
  1. 7
      CHANGELOG.md
  2. 117
      src/views/DIDView.vue
  3. 18
      test-playwright/00-noid-tests.spec.ts
  4. 22
      test-playwright/testUtils.ts

7
CHANGELOG.md

@ -6,6 +6,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [0.3.?]
### Added
- Separate 'isRegistered' flag for each account
### Fixed
- Alert when looking at one's own activity if not in contacts.
## [0.3.25] - 2024.08.30 - dcbe02d877aecb4cdef2643d90e6595d246a9f82
### Added
- "Ideas" now jumps directly to giving prompt or contact list.

117
src/views/DIDView.vue

@ -19,14 +19,17 @@
</div>
<!-- Identity Details -->
<div class="bg-slate-100 rounded-md overflow-hidden px-4 py-3 mb-4">
<div
v-if="!!contactFromDid"
class="bg-slate-100 rounded-md overflow-hidden px-4 py-3 mb-4"
>
<div>
<h2 class="text-xl font-semibold">
{{ contact?.name || "(no name)" }}
{{ contactFromDid?.name || "(no name)" }}
<button
@click="
contactEdit = true;
contactNewName = contact.name || '';
contactNewName = (contactFromDid?.name as string) || '';
"
title="Edit"
>
@ -49,12 +52,15 @@
>
</div>
<div class="flex justify-center mt-4">
<span v-if="contact?.profileImageUrl" class="flex justify-between">
<span
v-if="contactFromDid?.profileImageUrl"
class="flex justify-between"
>
<EntityIcon
:icon-size="96"
:profileImageUrl="contact?.profileImageUrl"
:profileImageUrl="contactFromDid?.profileImageUrl"
class="inline-block align-text-bottom border border-slate-300 rounded"
@click="showLargeIdenticonUrl = contact?.profileImageUrl"
@click="showLargeIdenticonUrl = contactFromDid?.profileImageUrl"
/>
</span>
</div>
@ -63,17 +69,21 @@
<div v-if="activeDid" class="flex justify-between">
<div>
<button
v-if="contact?.seesMe && contact.did !== activeDid"
v-if="
contactFromDid?.seesMe && contactFromDid.did !== activeDid
"
class="text-sm uppercase bg-gradient-to-b from-slate-400 to-slate-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white mx-0.5 my-0.5 px-2 py-1.5 rounded-md"
@click="confirmSetVisibility(contact, false)"
@click="confirmSetVisibility(contactFromDid, false)"
title="They can see you"
>
<fa icon="eye" class="fa-fw" />
</button>
<button
v-else-if="!contact?.seesMe && contact?.did !== activeDid"
v-else-if="
!contactFromDid?.seesMe && contactFromDid?.did !== activeDid
"
class="text-sm uppercase bg-gradient-to-b from-slate-400 to-slate-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white mx-0.5 my-0.5 px-2 py-1.5 rounded-md"
@click="confirmSetVisibility(contact, true)"
@click="confirmSetVisibility(contactFromDid, true)"
title="They cannot see you"
>
<fa icon="eye-slash" class="fa-fw" />
@ -83,9 +93,9 @@
<button
class="text-sm uppercase bg-gradient-to-b from-slate-400 to-slate-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white mx-0.5 my-0.5 px-2 py-1.5 rounded-md"
@click="checkVisibility(contact)"
@click="checkVisibility(contactFromDid)"
title="Check Visibility"
v-if="contact?.did !== activeDid"
v-if="contactFromDid?.did !== activeDid"
>
<fa icon="rotate" class="fa-fw" />
</button>
@ -94,13 +104,13 @@
</div>
<button
@click="confirmRegister(contact)"
@click="confirmRegister(contactFromDid)"
class="text-sm uppercase bg-gradient-to-b from-slate-400 to-slate-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white ml-6 mx-0.5 my-0.5 px-2 py-1.5 rounded-md"
v-if="contact?.did !== activeDid"
v-if="contactFromDid?.did !== activeDid"
title="Registration"
>
<fa
v-if="contact?.registered"
v-if="contactFromDid?.registered"
icon="person-circle-check"
class="fa-fw"
/>
@ -111,14 +121,14 @@
</div>
<button
@click="confirmDeleteContact(contact)"
@click="confirmDeleteContact(contactFromDid)"
class="text-sm uppercase bg-gradient-to-b from-rose-500 to-rose-800 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white ml-6 mx-0.5 my-0.5 px-2 py-1.5 rounded-md"
title="Delete"
>
<fa icon="trash-can" class="fa-fw" />
</button>
</div>
<div v-if="!contact?.profileImageUrl">
<div v-if="!contactFromDid?.profileImageUrl">
<div>Auto-Generated Icon</div>
<div class="flex justify-center">
<EntityIcon
@ -150,6 +160,15 @@
</div>
</div>
</div>
<div v-else class="bg-slate-100 rounded-md overflow-hidden px-4 py-3 mb-4">
<!-- !contactFromDid -->
<div>
<h2 class="text-xl font-semibold">
{{ isMyDid ? "You" : "(no name)" }}
</h2>
</div>
</div>
<div v-if="contactEdit" class="dialog-overlay">
<div class="dialog">
<h1 class="text-xl font-bold text-center mb-4">Edit Name</h1>
@ -222,7 +241,8 @@
v-if="!isLoading && claims.length === 0"
class="flex justify-center mt-4"
>
<span>They are in no claims visible to you.</span>
<span v-if="isMyDid">You have no claims yet.</span>
<span v-else>They are in no claims visible to you.</span>
</div>
</section>
</template>
@ -270,15 +290,15 @@ export default class DIDView extends Vue {
yaml = yaml;
activeDid = "";
allMyDids: Array<string> = [];
apiServer = "";
claims: Array<GenericCredWrapper<GenericVerifiableCredential>> = [];
contact: Contact;
contactFromDid?: Contact;
contactEdit = false;
contactNewName?: string;
contactNewName: string = "";
contactYaml = "";
hitEnd = false;
isLoading = false;
isMyDid = false;
searchBox: { name: string; bbox: BoundingBox } | null = null;
showDidDetails = false;
showLargeIdenticonId?: string;
@ -295,32 +315,23 @@ export default class DIDView extends Vue {
this.apiServer = settings.apiServer || "";
const pathParam = window.location.pathname.substring("/did/".length);
let theContact: Contact | undefined;
if (pathParam) {
this.viewingDid = decodeURIComponent(pathParam);
theContact = await db.contacts.get(this.viewingDid);
}
if (theContact) {
this.contact = theContact;
} else {
this.$notify(
{
group: "alert",
type: "danger",
title: "Error",
text: "No valid claim ID was provided.",
},
-1,
);
return;
this.contactFromDid = await db.contacts.get(this.viewingDid);
if (this.contactFromDid) {
this.contactYaml = yaml.dump(this.contactFromDid);
}
await this.loadClaimsAbout();
await accountsDB.open();
const allAccounts = await accountsDB.accounts.toArray();
for (const account of allAccounts) {
if (account.did === this.viewingDid) {
this.isMyDid = true;
break;
}
}
}
this.contactYaml = yaml.dump(this.contact);
await this.loadClaimsAbout();
await accountsDB.open();
const allAccounts = await accountsDB.accounts.toArray();
this.allMyDids = allAccounts.map((acc) => acc.did);
}
/**
@ -376,7 +387,7 @@ export default class DIDView extends Vue {
title: "Register",
text:
"Are you sure you want to register " +
libsUtil.nameForContact(this.contact, false) +
libsUtil.nameForContact(this.contactFromDid, false) +
(contact.registered
? " -- especially since they are already marked as registered"
: "") +
@ -557,9 +568,21 @@ export default class DIDView extends Vue {
}
private async onClickSaveName(newName: string) {
this.contact.name = newName;
if (!this.contactFromDid) {
this.$notify(
{
group: "alert",
type: "danger",
title: "Not A Contact",
text: "First add this on the contact page, then you can edit here.",
},
5000,
);
return;
}
this.contactFromDid.name = newName;
return db.contacts
.update(this.contact.did, { name: newName })
.update(this.contactFromDid.did, { name: newName })
.then(() => (this.contactEdit = false));
}

18
test-playwright/00-noid-tests.spec.ts

@ -1,5 +1,5 @@
import { test, expect } from '@playwright/test';
import { generateEthrUser, importUser } from './testUtils';
import { deleteContact, generateEthrUser, importUser } from './testUtils';
test('Check activity feed', async ({ page }) => {
// Load app homepage
@ -123,4 +123,20 @@ test('Check User 0 can register a random person', async ({ page }) => {
// now ensure that alert goes away
await page.locator('div[role="alert"] button > svg.fa-xmark').click(); // dismiss alert
await expect(page.getByText('That gift was recorded.')).toBeHidden();
// now delete the contact to test that pages still do reasonable things
await deleteContact(page, newDid);
// go the activity page for this new person
await page.goto('./did/' + encodeURIComponent(newDid));
let error;
try {
await page.waitForSelector('div[role="alert"]', { timeout: 2000 });
error = new Error('Error alert should not show.');
} catch (error) {
// success
} finally {
if (error) {
throw error;
}
}
});

22
test-playwright/testUtils.ts

@ -40,6 +40,22 @@ export async function switchToUser(page: Page, did: string): Promise<void> {
await page.getByRole('code', { name: did }).click();
}
function createContactName(did: string): string {
return "User " + did.slice(11, 14);
}
export async function deleteContact(page: Page, did: string): Promise<void> {
await page.goto('./contacts');
const contactName = createContactName(did);
// go to the detail page for this contact
await page.locator(`li[data-testid="contactListItem"] h2:has-text("${contactName}") + a`).click();
// delete the contact
await page.locator('button > svg.fa-trash-can').click();
await page.locator('div[role="alert"] button:has-text("Yes")').click();
// for some reason, .isHidden() (without expect) doesn't work
await expect(page.locator('div[role="alert"] button:has-text("Yes")')).toBeHidden();
}
// Generate a new random user and register them.
// Note that this makes 000 the active user. Use switchToUser to switch to this DID.
export async function generateEthrUser(page: Page): Promise<string> {
@ -55,10 +71,10 @@ export async function generateEthrUser(page: Page): Promise<string> {
await importUser(page, '000'); // switch to user 000
await page.goto('./contacts');
const threeChars = newDid.slice(11, 14);
await page.getByPlaceholder('URL or DID, Name, Public Key').fill(`${newDid}, User ${threeChars}`);
const contactName = createContactName(newDid);
await page.getByPlaceholder('URL or DID, Name, Public Key').fill(`${newDid}, ${contactName}`);
await page.locator('button > svg.fa-plus').click();
await page.locator('li', { hasText: threeChars }).click();
await page.locator('li', { hasText: contactName }).click();
// register them
await page.locator('div[role="alert"] button:has-text("Yes")').click();
// wait for it to disappear because the next steps may depend on alerts being gone

Loading…
Cancel
Save