Skip to content

Commit

Permalink
Merge pull request #8 from lightningrodlabs/feat/get-attachable-info
Browse files Browse the repository at this point in the history
Adds replaces getEntryInfo with getAttachableInfo
  • Loading branch information
matthme authored Jan 9, 2024
2 parents da67ae0 + a5a5961 commit 887bb41
Show file tree
Hide file tree
Showing 31 changed files with 436 additions and 401 deletions.
120 changes: 61 additions & 59 deletions example/ui/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@
<html lang="en">
<head>
<meta charset="utf-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, viewport-fit=cover"
/>
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
<meta name="Description" content="Example We Applet." />
<base href="/" />
<title>Example We Applet</title>
Expand All @@ -19,97 +16,100 @@
import '@shoelace-style/shoelace/dist/themes/light.css';
// import './src/example-applet.ts';
import { setBasePath } from '@shoelace-style/shoelace/dist/utilities/base-path';
import { WeClient, isWeContext, initializeHotReload } from "@lightningrodlabs/we-applet";
import "@lightningrodlabs/we-elements/dist/elements/we-client-context.js"
import { AttachmentsClient, AttachmentsStore } from "@lightningrodlabs/attachments";
import { CellType, encodeHashToBase64 } from "@holochain/client";
import { wrapPathInSvg } from "@holochain-open-dev/elements";
import { mdiPost } from "@mdi/js";
import { WeClient, isWeContext, initializeHotReload } from '@lightningrodlabs/we-applet';
import '@lightningrodlabs/we-elements/dist/elements/we-client-context.js';
import { AttachmentsClient, AttachmentsStore } from '@lightningrodlabs/attachments';
import { CellType, encodeHashToBase64 } from '@holochain/client';
import { wrapPathInSvg } from '@holochain-open-dev/elements';
import { mdiPost } from '@mdi/js';

import { ExampleApplet } from "./src/example-applet.ts";
import { PostsClient } from "./src/posts-client.ts";
import { PostsStore } from "./src/posts-store.ts";
import { ExampleApplet } from './src/example-applet.ts';
import { PostsClient } from './src/posts-client.ts';
import { PostsStore } from './src/posts-store.ts';


console.log("@example-applet: calling initializeHotReload");
console.log("@example-applet: initializeHotReload function: ", JSON.stringify(initializeHotReload));
console.log('@example-applet: calling initializeHotReload');
console.log(
'@example-applet: initializeHotReload function: ',
JSON.stringify(initializeHotReload)
);
if (import.meta.env.DEV) {
try {
await initializeHotReload();
} catch (e) {
console.warn("Could not initialize applet hot-reloading. This is only expected to work in a We context in dev mode.")
console.warn(
'Could not initialize applet hot-reloading. This is only expected to work in a We context in dev mode.'
);
}
}
console.log("Hot reload initialized.");

console.log("window.__WE_API__: ", window.__WE_API__);

console.log('Hot reload initialized.');

console.log("isWeContext? ", isWeContext());
console.log('window.__WE_API__: ', window.__WE_API__);

console.log('isWeContext? ', isWeContext());

setBasePath('shoelace');

(async function() {

(async function () {
const appletServices = {
attachmentTypes: async (appletClient, _appletHash, _weServices) => ({
"post": {
label: "post",
post: {
label: 'post',
icon_src: wrapPathInSvg(mdiPost),
create: async (attachToHrl) => {
const postsClient = new PostsClient(appletClient, "forum");
const postsClient = new PostsClient(appletClient, 'forum');
const post = {
title: "Attached Post",
content: "",
title: 'Attached Post',
content: '',
};
const postRecord = await postsClient.createPost(post);
console.warn("@example-applet: created post with postRecord: ", postRecord);
console.warn(`@example-applet: @create: postRecord.action ${postRecord.action} ; post.action() ${postRecord.action()} ; postRecord.actionHash ${postRecord.actionHash}; post.actionHash() ${postRecord.actionHash()};`);
console.warn('@example-applet: created post with postRecord: ', postRecord);
console.warn(
`@example-applet: @create: postRecord.action ${
postRecord.action
} ; post.action() ${postRecord.action()} ; postRecord.actionHash ${
postRecord.actionHash
}; post.actionHash() ${postRecord.actionHash()};`
);
const appInfo = await appletClient.appInfo();
const dnaHash = (appInfo.cell_info.forum[0])[
CellType.Provisioned
].cell_id[0];
const hrl = [
postRecord.actionHash,
dnaHash,
];
const dnaHash = appInfo.cell_info.forum[0][CellType.Provisioned].cell_id[0];
const hrl = [postRecord.actionHash, dnaHash];
return {
hrl,
context: {},
}
}
}
};
},
},
}),
blockTypes: {},
search: async (appletClient, _appletHash, _weServices, searchFilter) => {
const postsClient = new PostsClient(weClient.renderInfo.appletClient, "forum");
const postsClient = new PostsClient(weClient.renderInfo.appletClient, 'forum');
const appInfo = await appletClient.appInfo();
const dnaHash = (appInfo.cell_info.forum[0])[
CellType.Provisioned
].cell_id[0];
const dnaHash = appInfo.cell_info.forum[0][CellType.Provisioned].cell_id[0];
const allPosts = await postsClient.getAllPosts();
return allPosts
.map((postEntryRecord) => [postEntryRecord.entry, postEntryRecord.actionHash])
.filter(([post, _actionHash]) => post.title.toLowerCase().includes(searchFilter.toLowerCase()) ? true : false)
.filter(([post, _actionHash]) =>
post.title.toLowerCase().includes(searchFilter.toLowerCase()) ? true : false
)
.map(([post, actionHash]) => ({
hrl: [dnaHash, actionHash],
context: {},
}));
},
getEntryInfo: async (
getAttachableInfo: async (
appletClient,
roleName,
integrityZomeName,
entryType,
hrl
hrl,
_context
) => {
switch (roleName) {
case "forum":
case 'forum':
switch (integrityZomeName) {
case "posts_integrity":
case 'posts_integrity':
switch (entryType) {
case "post":
case 'post':
const postsClient = new PostsClient(appletClient, roleName);
const post = await postsClient.getPost(hrl[1]);
if (!post) return undefined;
Expand All @@ -126,20 +126,22 @@
default:
throw new Error(`Unknown role name '${roleName}'.`);
}
}
},
};

const weClient = await WeClient.connect(appletServices);
const provider = document.getElementById("provider");
const provider = document.getElementById('provider');
provider.weClient = weClient;

customElements.define("example-applet", ExampleApplet);
const exampleApplet = document.getElementById("example-applet");
exampleApplet.postsStore = new PostsStore(new PostsClient(weClient.renderInfo.appletClient, "forum"));
exampleApplet.attachmentsStore = new AttachmentsStore(new AttachmentsClient(weClient.renderInfo.appletClient, "forum"));

customElements.define('example-applet', ExampleApplet);
const exampleApplet = document.getElementById('example-applet');
exampleApplet.postsStore = new PostsStore(
new PostsClient(weClient.renderInfo.appletClient, 'forum')
);
exampleApplet.attachmentsStore = new AttachmentsStore(
new AttachmentsClient(weClient.renderInfo.appletClient, 'forum')
);
})();

</script>
</body>
</html>
6 changes: 2 additions & 4 deletions example/ui/src/example-applet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,17 +64,15 @@ export class ExampleApplet extends LitElement {
const appInfo = await client.appInfo();
const dnaHash = (appInfo.cell_info.forum[0] as any)[CellType.Provisioned]
.cell_id[0];
this.weClient!.openHrl([dnaHash, e.detail.postHash], {
detail: 'post',
});
this.weClient!.openHrl([dnaHash, e.detail.postHash], {});
}}
></applet-main>
</attachments-context>
</posts-context>
`;
case 'block':
throw new Error('Block view is not implemented.');
case 'entry':
case 'attachable':
switch (this.weClient.renderInfo.view.roleName) {
case 'forum':
switch (this.weClient.renderInfo.view.integrityZomeName) {
Expand Down
2 changes: 1 addition & 1 deletion libs/attachments/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@lightningrodlabs/attachments",
"version": "0.3.1",
"version": "0.4.0",
"main": "./dist/index.js",
"module": "./dist/index.js",
"exports": {
Expand Down
4 changes: 2 additions & 2 deletions libs/attachments/src/elements/add-attachment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export class AddAttachment extends LitElement {
const hrlWithContext = await this.weClient.userSelectHrl();
if (hrlWithContext) {
await this.attachmentsStore.client.addAttachment(this.hash, hrlWithContext);
notify(msg('Entry attached.'));
notify(msg('Attachable attached.'));
}
} catch (e) {
notifyError(msg('Error creating the attachment'));
Expand All @@ -61,7 +61,7 @@ export class AddAttachment extends LitElement {

render() {
return html`
<sl-tooltip content="Attach existing entry">
<sl-tooltip content="Attach existing attachable">
<div
class="row btn"
tabindex="0"
Expand Down
8 changes: 7 additions & 1 deletion libs/attachments/src/elements/create-attachment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ export class CreateAttachment extends LitElement {
@property(hashProperty('hash'))
hash!: AnyDhtHash;

@property()
context: any;

appletsInfosAndGroupsProfiles = new StoreSubscriber(
this,
() =>
Expand All @@ -63,7 +66,10 @@ export class CreateAttachment extends LitElement {
async createAttachment(attachmentType: AttachmentType) {
try {
const dnaHash = await this.attachmentsStore.client.getDnaHash();
const hrlWithContext = await attachmentType.create([dnaHash, this.hash]);
const hrlWithContext = await attachmentType.create({
hrl: [dnaHash, this.hash],
context: this.context,
});

await this.attachmentsStore.client.addAttachment(this.hash, hrlWithContext);
this.weClient.openHrl(hrlWithContext.hrl, hrlWithContext.context);
Expand Down
26 changes: 15 additions & 11 deletions libs/we-applet/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,18 @@ The differences between a We Applet and a normal Holochain App are:

- A We Applet can make use of the profiles zome provided by We instead of using its own profiles module
- A We Applet can provide more than just the default "main" UI. It can additionally provide:
- UI elements to display single DHT entries
- UI elements to display single "attachables"
- UI widgets/blocks of any kind
- UI elements ("main" view or "blocks") that render information across all instances of that same Applet type
- A We Applet can provide `AppletServices` for We or other Applets to use, including:
- search: Searching in the Applet that returns Holochain Resource Locators (HRLs) pointing to DHT content
- attachmentTypes: Entry types that can be attached by other Applets, alongside with a `create()` method that creates a new entry type to be attached ad hoc.
- getEntryInfo(): A function that returns info for the entry associated to the HRL if it exists in the Applet and the method is implemented.
- search: Searching in the Applet that returns Holochain Resource Locators (HRLs) with context pointing to an attachable
- attachmentTypes: Attachable types that can be attached by other Applets, alongside with a `create()` method that creates a new attachable to be attached ad hoc.
- getAttachableInfo(): A function that returns info for the attachable associated to the HrlWithContext if it exists in the Applet and the method is implemented.
- blockTypes: Types of UI widgets/blocks that this Applet can render if requested by We.

**Definition**: An "attachable" is anything that a) can be identified with an HRL plus arbitrary context and b) has an associated
"attachable-view", i.e. it can be displayed by the applet if requested.

### Implementing a most basic applet UI

```typescript=
Expand All @@ -41,7 +44,7 @@ const profilesClient = weClient.renderInfo.profilesClient;
### Implementing an (almost) full-fletched We Applet

```typescript=
import { WeClient, AppletServices, HrlWithContext, EntryInfo } from '@lightningrodlabs/we-applet';
import { WeClient, AppletServices, HrlWithContext, AttachableInfo } from '@lightningrodlabs/we-applet';
// First define your AppletServices that We can call on your applet
// to do things like search your applet or get information
Expand All @@ -52,9 +55,9 @@ const appletServices: Appletservices = {
'post': {
label: 'post',
icon_src: 'data:image/png;base64,iVBORasdwsfvawe',
create: (attachToHrl: Hrl) => {
// logic to create a new entry of that type. The attachToHrl can be used for
// backlinking, i.e. it is the HRL that the entry which is being
create: (attachToHrlWithContext: HrlWithContext) => {
// logic to create a new attachable of that type. The attachToHrlWithContext can be used for
// backlinking, i.e. it is the HrlWithContext that the attachable which is being
// created with this function is being attached to.
appletClient.callZome(...)
...
Expand All @@ -78,13 +81,14 @@ const appletServices: Appletservices = {
view: "cross-applet-view",
}
},
getEntryInfo: async (
getAttachableInfo: async (
appletClient: AppAgentClient,
roleName: RoleName,
integrityZomeName: ZomeName,
entryType: string,
hrl: Hrl,
): Promise<EntryInfo | undefined> => {
context: any,
): Promise<AttachableInfo | undefined> => {
// your logic here...
// for example
const post = appletClient.callZome({
Expand Down Expand Up @@ -137,7 +141,7 @@ switch (weClient.renderInfo.type) {
default:
throw new Error("Unknown applet-view block type");
}
case "entry":
case "attachable":
switch (weClient.renderInfo.view.roleName) {
case "forum":
switch (weClient.renderInfo.view.integrityZomeName) {
Expand Down
2 changes: 1 addition & 1 deletion libs/we-applet/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@lightningrodlabs/we-applet",
"version": "0.12.3",
"version": "0.13.0",
"main": "./dist/index.js",
"module": "./dist/index.js",
"exports": {
Expand Down
Loading

0 comments on commit 887bb41

Please sign in to comment.