From a07cc73594ee72cedb02a4e3f8d49d7d6f701c1e Mon Sep 17 00:00:00 2001 From: Eric Harris-Braun Date: Sun, 17 Dec 2023 12:15:46 -0500 Subject: [PATCH] boards can now be added as attachables --- ui/src/App.svelte | 3 +- ui/src/we.ts | 161 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 163 insertions(+), 1 deletion(-) create mode 100644 ui/src/we.ts diff --git a/ui/src/App.svelte b/ui/src/App.svelte index 7966715..4f2ea28 100644 --- a/ui/src/App.svelte +++ b/ui/src/App.svelte @@ -8,6 +8,7 @@ import "@holochain-open-dev/profiles/dist/elements/profile-prompt.js"; import "@holochain-open-dev/profiles/dist/elements/create-profile.js"; import TSLogoIcon from "./icons/TSLogoIcon.svelte"; + import { appletServices } from './we'; const appId = import.meta.env.VITE_APP_ID ? import.meta.env.VITE_APP_ID : 'talking-stickies' const roleName = 'talking-stickies' @@ -46,7 +47,7 @@ profilesClient = new ProfilesClient(client, appId); } else { - weClient = await WeClient.connect(); + weClient = await WeClient.connect(appletServices); if ( !(weClient.renderInfo.type === "applet-view") diff --git a/ui/src/we.ts b/ui/src/we.ts new file mode 100644 index 0000000..2ad1deb --- /dev/null +++ b/ui/src/we.ts @@ -0,0 +1,161 @@ +import { DocumentStore, SynClient, SynStore, WorkspaceStore } from '@holochain-syn/core'; +import { CellType, type AppAgentClient, type RoleName, type ZomeName, type EntryHash, type DnaHash } from '@holochain/client'; +import { Board, boardGrammar, type BoardGrammar } from './board'; +import { asyncDerived, pipe, sliceAndJoin, toPromise } from '@holochain-open-dev/stores'; +import { BoardType } from './boardList'; +import { LazyHoloHashMap } from '@holochain-open-dev/utils'; +import type { AppletHash, AppletServices, EntryInfo, Hrl, HrlWithContext, WeServices } from '@lightningrodlabs/we-applet'; + +const ROLE_NAME = "talking-stickies" +const ZOME_NAME = "syn" + +const getMyDna = async (client: AppAgentClient) : Promise => { + const appInfo = await client.appInfo(); + const dnaHash = (appInfo.cell_info[ROLE_NAME][0] as any)[ + CellType.Provisioned + ].cell_id[0]; + return dnaHash +} + +export const appletServices: AppletServices = { + // Types of attachment that this Applet offers for other Applets to attach + attachmentTypes: async ( + appletClient: AppAgentClient, + appletHash: AppletHash, + weServices: WeServices + ) => ({ + board: { + label: "Board", + icon_src: "https://static-00.iconduck.com/assets.00/kanban-icon-480x512-y56i8vrh.png", + async create(attachToHrl: Hrl) { + const synStore = new SynStore(new SynClient(appletClient, ROLE_NAME)); + const board = await Board.Create(synStore) + const dnaHash = await getMyDna(appletClient) + return { + hrl: [dnaHash, board.hash], + context: {}, + }; + }, + }, + }), + // Types of UI widgets/blocks that this Applet supports + blockTypes: {}, + getEntryInfo: async ( + appletClient: AppAgentClient, + roleName: RoleName, + integrityZomeName: ZomeName, + entryType: string, + hrl: Hrl + ): Promise => { + + const synClient = new SynClient(appletClient, roleName, ZOME_NAME); + const synStore = new SynStore(synClient); + const documentHash = hrl[1] + const docStore = new DocumentStore(synStore, boardGrammar, documentHash) + const workspaces = await toPromise(docStore.allWorkspaces) + const workspace = new WorkspaceStore(docStore, Array.from(workspaces.keys())[0]) + const latestSnapshot = await toPromise(workspace.latestSnapshot) + + return { + icon_src: "https://static-00.iconduck.com/assets.00/kanban-icon-480x512-y56i8vrh.png", + name: latestSnapshot.name, + }; + }, + search: async ( + appletClient: AppAgentClient, + appletHash: AppletHash, + weServices: WeServices, + searchFilter: string + ): Promise> => { + const synClient = new SynClient(appletClient, ROLE_NAME, ZOME_NAME); + const synStore = new SynStore(synClient); + const boardHashes = asyncDerived(synStore.documentsByTag.get(BoardType.active),x=>Array.from(x.keys())) + + const documents: LazyHoloHashMap> = new LazyHoloHashMap( documentHash => + new DocumentStore(synStore, boardGrammar, documentHash)) + + const boardData = new LazyHoloHashMap( documentHash => { + const docStore = documents.get(documentHash) + + const workspace = pipe(docStore.allWorkspaces, + workspaces => { + return new WorkspaceStore(docStore, Array.from(workspaces.keys())[0]) + } + ) + const latestState = pipe(workspace, + w => w.latestSnapshot + ) + return latestState + }) + + const allBoardsAsync = pipe(boardHashes, + docHashes => sliceAndJoin(boardData, docHashes) + ) + + const allBoards = Array.from((await toPromise(allBoardsAsync)).entries()) + const dnaHash = await getMyDna(appletClient) + + return allBoards + .filter((r) => !!r) + .filter((r) => { + const state = r[1] + return state.name.toLowerCase().includes(searchFilter.toLowerCase()) + }) + .map((r) => ({ hrl: [dnaHash, r![0]], context: {} })); + }, +}; + + +// // Then handle all the different types of views that you offer +// switch (weClient.renderInfo.type) { +// case "applet-view": +// switch (weClient.renderInfo.view.type) { +// case "main": +// // here comes your rendering logic for the main view +// case "block": +// switch(weClient.renderInfo.view.block) { +// case "most_recent_posts": +// // your rendering logic to display this block type +// case "bookmarked_posts": +// // Your rendering logic to display this block type +// default: +// throw new Error("Unknown applet-view block type"); +// } +// case "entry": +// switch (weClient.renderInfo.view.roleName) { +// case "forum": +// switch (weClient.renderInfo.view.integrityZomeName) { +// case "posts_integrity": +// switch (weClient.renderInfo.view.entryType) { +// case "post": +// // here comes your rendering logic for that specific entry type +// default: +// throw new Error("Unknown entry type"); +// } +// default: +// throw new Error("Unknown integrity zome"); +// } +// default: +// throw new Error("Unknown role name"); +// } + +// default: +// throw new Error("Unknown applet-view type"); +// } + +// case "cross-applet-view": +// switch (this.weClient.renderInfo.view.type) { +// case "main": +// // here comes your rendering logic for the cross-applet main view +// case "block": +// // +// default: +// throw new Error("Unknown cross-applet-view render type.") + +// `; +// } + +// default: +// throw new Error("Unknown render view type"); + +// }