forked from trent_larson/crowd-funder-for-time-pwa
fix alert when looking at one's own activity
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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();
|
||||
|
||||
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);
|
||||
await accountsDB.open();
|
||||
const allAccounts = await accountsDB.accounts.toArray();
|
||||
for (const account of allAccounts) {
|
||||
if (account.did === this.viewingDid) {
|
||||
this.isMyDid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user