Skip to content

Commit

Permalink
feat: list address books
Browse files Browse the repository at this point in the history
  • Loading branch information
angelo-v committed Apr 17, 2024
1 parent d9fc8e7 commit e654d19
Show file tree
Hide file tree
Showing 10 changed files with 216 additions and 13 deletions.
2 changes: 1 addition & 1 deletion contacts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"dependencies": {
"@pod-os/core": "^0.11.1",
"@pod-os/elements": "^0.16.0",
"@solid-data-modules/contacts-rdflib": "^0.4.0",
"@solid-data-modules/contacts-rdflib": "^0.5.0",
"@stencil/core": "^4.12.4",
"netlify-cli": "^17.22.1",
"pollen-css": "^4.6.2"
Expand Down
16 changes: 16 additions & 0 deletions contacts/src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ export interface PosContactsGroupListCustomEvent<T> extends CustomEvent<T> {
detail: T;
target: HTMLPosContactsGroupListElement;
}
export interface PosContactsListAddressBooksCustomEvent<T> extends CustomEvent<T> {
detail: T;
target: HTMLPosContactsListAddressBooksElement;
}
export interface PosContactsOpenAddressBookCustomEvent<T> extends CustomEvent<T> {
detail: T;
target: HTMLPosContactsOpenAddressBookElement;
Expand Down Expand Up @@ -199,7 +203,18 @@ declare global {
prototype: HTMLPosContactsGroupListElement;
new (): HTMLPosContactsGroupListElement;
};
interface HTMLPosContactsListAddressBooksElementEventMap {
"pod-os:module": any;
}
interface HTMLPosContactsListAddressBooksElement extends Components.PosContactsListAddressBooks, HTMLStencilElement {
addEventListener<K extends keyof HTMLPosContactsListAddressBooksElementEventMap>(type: K, listener: (this: HTMLPosContactsListAddressBooksElement, ev: PosContactsListAddressBooksCustomEvent<HTMLPosContactsListAddressBooksElementEventMap[K]>) => any, options?: boolean | AddEventListenerOptions): void;
addEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
addEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
removeEventListener<K extends keyof HTMLPosContactsListAddressBooksElementEventMap>(type: K, listener: (this: HTMLPosContactsListAddressBooksElement, ev: PosContactsListAddressBooksCustomEvent<HTMLPosContactsListAddressBooksElementEventMap[K]>) => any, options?: boolean | EventListenerOptions): void;
removeEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
removeEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
}
var HTMLPosContactsListAddressBooksElement: {
prototype: HTMLPosContactsListAddressBooksElement;
Expand Down Expand Up @@ -322,6 +337,7 @@ declare namespace LocalJSX {
"onPod-os-contacts:group-selected"?: (event: PosContactsGroupListCustomEvent<Group>) => void;
}
interface PosContactsListAddressBooks {
"onPod-os:module"?: (event: PosContactsListAddressBooksCustomEvent<any>) => void;
"webId": string;
}
interface PosContactsLoadingSpinner {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Component, h, Host, Listen, Prop, State, Watch } from '@stencil/core';

@Component({
tag: 'pos-contacts-address-book-page',
styleUrl: 'address-book-page.css',
styleUrl: './address-book-page.css',
shadow: true,
})
export class AddressBookPage {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
ul {
margin: 0;
padding: 0;
list-style-type: none;
}
48 changes: 45 additions & 3 deletions contacts/src/components/list-address-books/list-address-books.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,54 @@
import { Component, h, Prop } from '@stencil/core';
import { AddressBookLists, ContactsModule } from '@solid-data-modules/contacts-rdflib';
import { Component, Event, h, Prop, State, Watch } from '@stencil/core';
import { PodOsModuleAware, PodOsModuleEventEmitter, subscribePodOsModule } from '../../events/PodOsModuleAware';

@Component({
tag: 'pos-contacts-list-address-books',
styleUrl: './list-address-books.css',
shadow: true,
})
export class ListAddressBooks {
export class ListAddressBooks implements PodOsModuleAware<ContactsModule> {
@Prop()
webId!: string;

@State()
private contactsModule: ContactsModule;

@Event({ eventName: 'pod-os:module' })
subscribeModule: PodOsModuleEventEmitter<ContactsModule>;

@State()
private addressBookLists: AddressBookLists;

componentWillLoad() {
subscribePodOsModule('contacts', this);
}

receiveModule = (module: ContactsModule) => {
this.contactsModule = module;
};

@Watch('contactsModule')
async listAddressBooks() {
this.addressBookLists = await this.contactsModule.listAddressBooks(this.webId);
}

render() {
return <div>TODO: list address books of {this.webId}</div>;
if (!this.addressBookLists) {
return <div>Loading...</div>;
}
const allUris = [...this.addressBookLists.privateUris, ...this.addressBookLists.publicUris];
if (allUris.length == 0) {
return <div>Sorry, no address books could be found in your pod.</div>;
}
return (
<ul>
{allUris.map(uri => (
<li>
<pos-rich-link uri={uri}></pos-rich-link>
</li>
))}
</ul>
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import { AddressBookLists, ContactsModule } from '@solid-data-modules/contacts-rdflib';
import { h } from '@stencil/core';
import { newSpecPage } from '@stencil/core/testing';
import { when } from 'jest-when';
import { ListAddressBooks } from '../list-address-books';

describe('list address books', () => {
let page;
beforeEach(async () => {
page = await newSpecPage({
components: [ListAddressBooks],
template: () => <pos-contacts-list-address-books webId="https://alice.test/profile/card#me" />,
supportsShadowDom: false,
});
});

it('shows loading indicator initially', () => {
expect(page.root).toEqualHtml(`
<pos-contacts-list-address-books>
<div>Loading...</div>
</pos-contacts-list-address-books>`);
});

it('indicates that now address books have been found', async () => {
const module = {
listAddressBooks: jest.fn() as unknown,
} as ContactsModule;

const lists: AddressBookLists = {
publicUris: [],
privateUris: [],
};

when(module.listAddressBooks).calledWith('https://alice.test/profile/card#me').mockResolvedValue(lists);

page.rootInstance.receiveModule(module);
await page.waitForChanges();

expect(page.root).toEqualHtml(`
<pos-contacts-list-address-books>
<div>Sorry, no address books could be found in your pod.</div>
</pos-contacts-list-address-books>`);
});

it('lists a single private address book', async () => {
const module = {
listAddressBooks: jest.fn() as unknown,
} as ContactsModule;

const lists: AddressBookLists = {
publicUris: [],
privateUris: ['https://alice.test/private/contacts/1'],
};

when(module.listAddressBooks).calledWith('https://alice.test/profile/card#me').mockResolvedValue(lists);

page.rootInstance.receiveModule(module);
await page.waitForChanges();

expect(page.root).toEqualHtml(`
<pos-contacts-list-address-books>
<ul>
<li>
<pos-rich-link uri="https://alice.test/private/contacts/1"></pos-rich-link>
</li>
</ul>
</pos-contacts-list-address-books>`);
});

it('lists a single public address book', async () => {
const module = {
listAddressBooks: jest.fn() as unknown,
} as ContactsModule;

const lists: AddressBookLists = {
publicUris: ['https://alice.test/public/contacts/1'],
privateUris: [],
};

when(module.listAddressBooks).calledWith('https://alice.test/profile/card#me').mockResolvedValue(lists);

page.rootInstance.receiveModule(module);
await page.waitForChanges();

expect(page.root).toEqualHtml(`
<pos-contacts-list-address-books>
<ul>
<li>
<pos-rich-link uri="https://alice.test/public/contacts/1"></pos-rich-link>
</li>
</ul>
</pos-contacts-list-address-books>`);
});

it('lists all address books', async () => {
const module = {
listAddressBooks: jest.fn() as unknown,
} as ContactsModule;

const lists: AddressBookLists = {
publicUris: ['https://alice.test/public/contacts/1'],
privateUris: ['https://alice.test/private/contacts/1', 'https://alice.test/private/contacts/2'],
};

when(module.listAddressBooks).calledWith('https://alice.test/profile/card#me').mockResolvedValue(lists);

page.rootInstance.receiveModule(module);
await page.waitForChanges();

expect(page.root).toEqualHtml(`
<pos-contacts-list-address-books>
<ul>
<li>
<pos-rich-link uri="https://alice.test/private/contacts/1"></pos-rich-link>
</li>
<li>
<pos-rich-link uri="https://alice.test/private/contacts/2"></pos-rich-link>
</li>
<li>
<pos-rich-link uri="https://alice.test/public/contacts/1"></pos-rich-link>
</li>
</ul>
</pos-contacts-list-address-books>`);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ export class OpenAddressBook {
@Prop()
webId: string | undefined;

@Listen('pod-os:link')
openFromLink(event: CustomEvent<string>) {
console.log(event);
this.openAddressBook.emit(event.detail);
}

promptAndOpen() {
const uri = prompt('Please enter URI of an address book', 'http://localhost:3000/alice/public-contacts/index.ttl#this');
if (uri) {
Expand Down
2 changes: 1 addition & 1 deletion core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
},
"dependencies": {
"@inrupt/solid-client-authn-browser": "^1.17.5",
"@solid-data-modules/contacts-rdflib": "^0.4.0",
"@solid-data-modules/contacts-rdflib": "^0.5.0",
"@types/lunr": "^2.3.7",
"buffer": "^6.0.3",
"lunr": "^2.3.9",
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"key":"setup/current-server-version","payload":"7.0.3"}
{"key":"setup/current-server-version","payload":"7.0.4"}
21 changes: 15 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit e654d19

Please sign in to comment.