From fcff8d5c0879ed93ab9f890c3d739cb788582e2e Mon Sep 17 00:00:00 2001 From: Eric Harris-Braun Date: Thu, 7 Dec 2023 12:10:59 -0500 Subject: [PATCH] added reparenting of tree elements --- .../how/zomes/coordinator/how/src/document.rs | 10 +- dnas/how/zomes/coordinator/how/src/tree.rs | 84 +++++++++++++--- dnas/how/zomes/coordinator/how/src/unit.rs | 95 +++++++++++++++++- package-lock.json | 98 ++++++------------- ui/package.json | 2 +- ui/src/elements/how-agent-list.ts | 2 +- ui/src/elements/how-controller.ts | 63 +++++++++++- ui/src/elements/how-tree.ts | 2 +- ui/src/elements/how-unit-dialog.ts | 2 +- ui/src/elements/how-unit.ts | 7 +- ui/src/elements/svg-button.ts | 20 ++++ ui/src/holochain-app.ts | 2 +- ui/src/how.service.ts | 5 + ui/src/how.store.ts | 4 + ui/src/types.ts | 2 +- 15 files changed, 304 insertions(+), 94 deletions(-) diff --git a/dnas/how/zomes/coordinator/how/src/document.rs b/dnas/how/zomes/coordinator/how/src/document.rs index 70942ac..7bf1cb0 100644 --- a/dnas/how/zomes/coordinator/how/src/document.rs +++ b/dnas/how/zomes/coordinator/how/src/document.rs @@ -131,10 +131,14 @@ pub struct UpdateDocumentInput { pub fn update_document(input: UpdateDocumentInput) -> ExternResult { let record = get(EntryHash::from(input.hash), GetOptions::default())? .ok_or(wasm_error!(WasmErrorInner::Guest(String::from("Document not found"))))?; - let _action_hash = update_entry(record.action_address().clone().into(), &input.document)?; - let hash = hash_entry(&input.document)?; + _update_document(record.action_address().clone().into(),input.path, &input.document) +} + +pub fn _update_document(hash: ActionHash, path: String, document: &Document) -> ExternResult { + let _action_hash = update_entry(hash, document)?; + let hash = hash_entry(document)?; // TODO validate that old doc had the same path, or get the path some other way? - link_document(hash.clone(), input.path)?; + link_document(hash.clone(), path)?; return Ok(hash.into()); } diff --git a/dnas/how/zomes/coordinator/how/src/tree.rs b/dnas/how/zomes/coordinator/how/src/tree.rs index ed327e5..f7e50f5 100644 --- a/dnas/how/zomes/coordinator/how/src/tree.rs +++ b/dnas/how/zomes/coordinator/how/src/tree.rs @@ -13,11 +13,19 @@ pub struct UnitInfo { #[derive(Clone, Serialize, Deserialize, Debug, Default, PartialEq)] pub struct Content { - name: String, - units: Vec, - documents: Vec, + pub name: String, + pub units: Vec, + pub documents: Vec, } +#[derive(Clone, Debug, Default, PartialEq)] +pub struct PathContent { + pub path: String, + pub units: Vec, + pub documents: Vec, +} + + fn get_entry_hashes(path: &Path) -> ExternResult<(Vec,Vec)> { let mut units = vec![]; let mut documents = vec![]; @@ -48,13 +56,34 @@ fn build_tree(tree: &mut Tree, node: usize, path: Path) -> ExternResult for path in path.into_typed(ScopedLinkType::try_from(LinkTypes::Tree)?).children_paths()? { let v = path.as_ref(); let (units, documents) = get_entry_hashes(&path)?; - let val = Content { - name: String::try_from(&v[v.len()-1]).map_err(|e| wasm_error!(e))?, - units, - documents, - }; - let idx = tree.insert(node, val); - build_tree(tree, idx, path.path)?; + // there may be a path left over from a move that is now empty, so ignore it if there are no units there. + if units.len() > 0 { + let val = Content { + name: String::try_from(&v[v.len()-1]).map_err(|e| wasm_error!(e))?, + units, + documents, + }; + let idx = tree.insert(node, val); + build_tree(tree, idx, path.path)?; + } + } + Ok(()) +} + + +fn build_path_tree(tree: &mut Tree, node: usize, path: Path) -> ExternResult<()>{ + for path in path.into_typed(ScopedLinkType::try_from(LinkTypes::Tree)?).children_paths()? { + let path_str : String = path.clone().try_into().map_err(|_e| wasm_error!(WasmErrorInner::Guest(String::from("XXX"))))?; + let (units, documents) = get_entry_hashes(&path)?; + if units.len() > 0 { + let val = PathContent { + path: path_str, + units, + documents, + }; + let idx = tree.insert(node, val); + build_path_tree(tree, idx, path.path)?; + } } Ok(()) } @@ -66,9 +95,23 @@ pub fn tree_path(path_str: String) -> Path { Path::from(path) } +pub fn tree_path_to_str(path:Path) -> ExternResult { + let mut v = path.as_ref().clone(); + v.remove(0); + let mut x:Vec = Vec::new(); + for c in v { + x.push(String::try_from(&c).map_err(|e| wasm_error!(e))?); + } + Ok(x.join(".")) +} + #[hdk_extern] pub fn get_tree(_input: ()) -> ExternResult> { let root_path = Path::from(TREE_ROOT); + _get_tree(root_path) +} + +pub fn _get_tree(root_path: Path) -> ExternResult> { let (units, documents) = get_entry_hashes(&root_path)?; let val = Content { name: String::from(""), @@ -80,6 +123,19 @@ pub fn get_tree(_input: ()) -> ExternResult> { Ok(tree) } +pub fn _get_path_tree(root_path: Path) -> ExternResult> { + let (units, documents) = get_entry_hashes(&root_path)?; + let val = PathContent { + path: tree_path_to_str(root_path.clone())?, + units, + documents, + }; + let mut tree = Tree::new(val); + build_path_tree(&mut tree, 0, root_path)?; + Ok(tree) +} + + #[derive(Clone, Serialize, Deserialize, Debug, Default)] pub struct Tree where @@ -118,10 +174,10 @@ pub struct Node where T: PartialEq { - idx: usize, - val: T, - parent: Option, - children: Vec, + pub idx: usize, + pub val: T, + pub parent: Option, + pub children: Vec, } impl Node diff --git a/dnas/how/zomes/coordinator/how/src/unit.rs b/dnas/how/zomes/coordinator/how/src/unit.rs index c2c5df0..a53aaf7 100644 --- a/dnas/how/zomes/coordinator/how/src/unit.rs +++ b/dnas/how/zomes/coordinator/how/src/unit.rs @@ -6,10 +6,10 @@ use holo_hash::{EntryHashB64}; use how_integrity::Document; use how_integrity::{Unit, EntryTypes, LinkTypes}; -use crate::document::{update_document, UpdateDocumentInput}; +use crate::document::{update_document, UpdateDocumentInput, _update_document}; use crate::error::*; //use crate::signals::*; -use crate::tree::UnitInfo; +use crate::tree::{UnitInfo, _get_tree, tree_path, _get_path_tree, tree_path_to_str}; pub fn get_units_path() -> Path { Path::from("units") @@ -181,3 +181,94 @@ pub fn advance_state(input: AdvanceStateInput) -> ExternResult { create_unit_links(hash,unit.tree_paths(), &input.new_state, &unit.version)?; return Ok(new_doc_hash); } + + +#[derive(Clone, Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct ReparentInput { + pub path: String, + pub new_parent: String, +} +#[hdk_extern] +pub fn reparent(input: ReparentInput) -> ExternResult<()> { + // let new_parent_path = Path::from(input.new_parent); + // let link = get + let sub_tree = _get_path_tree(tree_path(input.path.clone()))?; + let mut parent:Vec<_> = input.path.split(".").into_iter().collect(); + parent.pop(); + let parent = parent.join("."); + for node in sub_tree.tree { + let units = node.val.units.clone(); + let current_path = node.val.path;//.clone(); + for unit in units { + let documents: Vec> = node.val.documents.clone(); + + let (new_unit_hash, new_unit) = reparent_unit(&unit, parent.clone(), input.new_parent.clone())?; + for doc in documents { + reparent_document(unit.hash.clone(), new_unit_hash.clone(), &new_unit, doc, current_path.clone(), input.new_parent.clone())?; + } + } + } + Ok(()) +} + +pub fn update_unit(hash: ActionHash, unit: &Unit) -> ExternResult { + let _action_hash = update_entry(hash, unit)?; + let hash = hash_entry(unit)?; + Ok(hash) +} + +pub fn reparent_unit(unit_info: &UnitInfo, from: String, to: String) -> ExternResult<(EntryHash, Unit)> { + let record = get(unit_info.hash.clone(), GetOptions::default())? + .ok_or(wasm_error!(WasmErrorInner::Guest(String::from("Unit not found"))))?; + let mut unit: Unit = record + .entry() + .to_app_option().map_err(|err| wasm_error!(err))? + .ok_or(wasm_error!(WasmErrorInner::Guest(String::from("Malformed unit"))))?; + delete_unit_links(unit_info.hash.clone(), unit.tree_paths())?; + + if let Some(idx) = unit.parents.clone().into_iter().position(|p| { + p.starts_with(&from)} + ) { + unit.parents[idx] = unit.parents[idx].replacen(&from, &to,1); + } + + let new_unit_hash = update_unit(record.action_address().clone(), &unit)?; + create_unit_links(new_unit_hash.clone(), unit.tree_paths(), &unit_info.state, &unit_info.version)?; + + Ok((new_unit_hash,unit)) +} + +pub fn reparent_document(old_unit_hash: EntryHash, new_unit_hash: EntryHash, new_unit: &Unit, hash: EntryHash, old_path:String, new_parent: String) -> ExternResult<()> { + let record = get(hash.clone(), GetOptions::default())? + .ok_or(wasm_error!(WasmErrorInner::Guest(String::from("Document not found"))))?; + let mut document: Document = record + .entry() + .to_app_option().map_err(|err| wasm_error!(err))? + .ok_or(wasm_error!(WasmErrorInner::Guest(String::from("Malformed document"))))?; + + if document.unit_hash == old_unit_hash { + document.unit_hash = new_unit_hash; + let new_path = format!("{}.{}", new_parent, new_unit.path_abbreviation); + let path = tree_path(old_path); + let links = get_links(path.path_entry_hash()?, LinkTypes::Document, None)?; + + // delete all the old links at the old path + let mut delete_link_input: Vec = Vec::new(); + let any: AnyLinkableHash = hash.into(); + for l in links { + if l.target == any { + delete_link_input.push(DeleteLinkInput{ + address: l.create_link_hash, + chain_top_ordering: ChainTopOrdering::Relaxed, + }); + } + } + for input in delete_link_input { + HDK.with(|hdk| hdk.borrow().delete_link(input))?; + } + + _update_document( record.action_address().clone().into(), new_path, &document )?; + } + Ok(()) +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index a10b26f..6ed14f0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -927,15 +927,6 @@ "@holochain/client": "0.16.6" } }, - "node_modules/@lit-labs/context": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@lit-labs/context/-/context-0.2.0.tgz", - "integrity": "sha512-WU01ysdm+6LwLeFRD9PirdbE1OYefL2ZKFZcpOLMJulaQDYqeqZtOUfccO63CTuLrQkG61VGiVycMoHFqgXx8A==", - "dependencies": { - "@lit/reactive-element": "^1.5.0", - "lit": "^2.5.0" - } - }, "node_modules/@lit-labs/ssr-dom-shim": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.1.2.tgz", @@ -961,6 +952,7 @@ "version": "0.11.4", "resolved": "https://registry.npmjs.org/@lit/localize/-/localize-0.11.4.tgz", "integrity": "sha512-RRIwIX2tAm3+DuEndoXSJrFjGrAK5cb5IXo5K6jcJ6sbgD829B8rSqHC5MaKVUmXTVLIR1bk5IZOZDf9wFereA==", + "dev": true, "dependencies": { "@lit/reactive-element": "^1.4.0", "lit": "^2.3.0" @@ -3182,10 +3174,6 @@ "node": ">= 8" } }, - "node_modules/app": { - "resolved": "ui", - "link": true - }, "node_modules/archiver": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.1.tgz", @@ -6191,6 +6179,10 @@ "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", "dev": true }, + "node_modules/how-app-ui": { + "resolved": "ui", + "link": true + }, "node_modules/htmlparser2": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-7.2.0.tgz", @@ -9766,7 +9758,7 @@ } }, "ui": { - "name": "app", + "name": "how-app-ui", "version": "0.0.0", "license": "MIT", "dependencies": { @@ -9777,16 +9769,16 @@ "@holochain-open-dev/utils": "^0.16.0", "@holochain/client": "0.16", "@lightningrodlabs/we-applet": "0.12.0", - "@lit-labs/context": "^0.2.0", - "@lit/localize": "^0.11.4", + "@lit/context": "^1.0.0", + "@lit/localize": "^0.12.0", "@open-wc/scoped-elements": "^2.1.4", "@scoped-elements/material-web": "0.0.19", - "@shoelace-style/shoelace": "^2.5.2", + "@shoelace-style/shoelace": "^2.12", "@ts-stack/markdown": "^1.4.0", "@types/javascript-time-ago": "^2.0.3", "@types/sanitize-html": "=2.6.2", "javascript-time-ago": "2.3.7", - "lit": "^2.7.0", + "lit": "^3.0.0", "sanitize-filename": "1.6.3", "wc-mermaid": "github:guillemcordoba/wc-mermaid#patch-1" }, @@ -9823,7 +9815,7 @@ "@holochain-open-dev/stores": "^0.6.0", "@holochain-open-dev/utils": "^0.15.0", "@holochain/client": "^0.16", - "@lit-labs/context": "^0.2.0", + "@lit/context": "^0.2.0", "@lit/localize": "^0.11.4", "@open-wc/scoped-elements": "^2.1.4", "@shoelace-style/shoelace": "^2.5.2", @@ -9868,7 +9860,7 @@ "@holochain-open-dev/utils": "^0.12.0", "@holochain/client": "^0.12.0", "@holochain/how": "^0.1.0", - "@lit-labs/context": "^0.2.0", + "@lit/context": "^0.2.0", "@lit/localize": "^0.11.4", "lit": "^2.7.0" }, @@ -9914,8 +9906,8 @@ "@holochain-open-dev/stores": "^0.6.0", "@holochain-open-dev/utils": "^0.15.0", "@holochain/client": "^0.16", - "@lit-labs/context": "^0.2.0", "@lit-labs/task": "^2.0.0", + "@lit/context": "^0.2.0", "@lit/localize": "^0.11.4", "@mdi/js": "^7.2.96", "@msgpack/msgpack": "^2.7.2", @@ -9983,24 +9975,6 @@ "svelte": "^3.53.1" } }, - "ui/node_modules/@holochain-open-dev/elements/node_modules/@lit/localize": { - "version": "0.12.1", - "resolved": "https://registry.npmjs.org/@lit/localize/-/localize-0.12.1.tgz", - "integrity": "sha512-uuF6OO6fjqomCf3jXsJ5cTGf1APYuN88S4Gvo/fjt9YkG4OMaMvpEUqd5oWhyzrJfY+HcenAbLJNi2Cq3H7gdg==", - "dependencies": { - "lit": "^2.0.0 || ^3.0.0" - } - }, - "ui/node_modules/@holochain-open-dev/elements/node_modules/lit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/lit/-/lit-3.1.0.tgz", - "integrity": "sha512-rzo/hmUqX8zmOdamDAeydfjsGXbbdtAFqMhmocnh2j9aDYqbu0fjXygjCa0T99Od9VQ/2itwaGrjZz/ZELVl7w==", - "dependencies": { - "@lit/reactive-element": "^2.0.0", - "lit-element": "^4.0.0", - "lit-html": "^3.1.0" - } - }, "ui/node_modules/@holochain-open-dev/elements/node_modules/lit-svelte-stores": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/lit-svelte-stores/-/lit-svelte-stores-0.3.2.tgz", @@ -10027,24 +10001,6 @@ "lit": "^3.0.2" } }, - "ui/node_modules/@holochain-open-dev/profiles/node_modules/@lit/localize": { - "version": "0.12.1", - "resolved": "https://registry.npmjs.org/@lit/localize/-/localize-0.12.1.tgz", - "integrity": "sha512-uuF6OO6fjqomCf3jXsJ5cTGf1APYuN88S4Gvo/fjt9YkG4OMaMvpEUqd5oWhyzrJfY+HcenAbLJNi2Cq3H7gdg==", - "dependencies": { - "lit": "^2.0.0 || ^3.0.0" - } - }, - "ui/node_modules/@holochain-open-dev/profiles/node_modules/lit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/lit/-/lit-3.1.0.tgz", - "integrity": "sha512-rzo/hmUqX8zmOdamDAeydfjsGXbbdtAFqMhmocnh2j9aDYqbu0fjXygjCa0T99Od9VQ/2itwaGrjZz/ZELVl7w==", - "dependencies": { - "@lit/reactive-element": "^2.0.0", - "lit-element": "^4.0.0", - "lit-html": "^3.1.0" - } - }, "ui/node_modules/@holochain-open-dev/stores": { "version": "0.8.3", "resolved": "https://registry.npmjs.org/@holochain-open-dev/stores/-/stores-0.8.3.tgz", @@ -10060,16 +10016,6 @@ "svelte": "^3.53.1" } }, - "ui/node_modules/@holochain-open-dev/stores/node_modules/lit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/lit/-/lit-3.1.0.tgz", - "integrity": "sha512-rzo/hmUqX8zmOdamDAeydfjsGXbbdtAFqMhmocnh2j9aDYqbu0fjXygjCa0T99Od9VQ/2itwaGrjZz/ZELVl7w==", - "dependencies": { - "@lit/reactive-element": "^2.0.0", - "lit-element": "^4.0.0", - "lit-html": "^3.1.0" - } - }, "ui/node_modules/@holochain-open-dev/stores/node_modules/lit-svelte-stores": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/lit-svelte-stores/-/lit-svelte-stores-0.3.2.tgz", @@ -10113,6 +10059,14 @@ "node": ">=18.0.0 || >=20.0.0" } }, + "ui/node_modules/@lit/localize": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/@lit/localize/-/localize-0.12.1.tgz", + "integrity": "sha512-uuF6OO6fjqomCf3jXsJ5cTGf1APYuN88S4Gvo/fjt9YkG4OMaMvpEUqd5oWhyzrJfY+HcenAbLJNi2Cq3H7gdg==", + "dependencies": { + "lit": "^2.0.0 || ^3.0.0" + } + }, "ui/node_modules/@lit/reactive-element": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-2.0.2.tgz", @@ -10179,6 +10133,16 @@ "node": ">=4" } }, + "ui/node_modules/lit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lit/-/lit-3.1.0.tgz", + "integrity": "sha512-rzo/hmUqX8zmOdamDAeydfjsGXbbdtAFqMhmocnh2j9aDYqbu0fjXygjCa0T99Od9VQ/2itwaGrjZz/ZELVl7w==", + "dependencies": { + "@lit/reactive-element": "^2.0.0", + "lit-element": "^4.0.0", + "lit-html": "^3.1.0" + } + }, "ui/node_modules/lit-element": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/lit-element/-/lit-element-4.0.2.tgz", diff --git a/ui/package.json b/ui/package.json index bf698e0..f94bc17 100644 --- a/ui/package.json +++ b/ui/package.json @@ -14,7 +14,7 @@ "dependencies": { "@scoped-elements/material-web": "0.0.19", "@open-wc/scoped-elements": "^2.1.4", - "@shoelace-style/shoelace": "^2.5.2", + "@shoelace-style/shoelace": "^2.12", "@fortawesome/free-solid-svg-icons": "^6.3.0", "@holochain-open-dev/elements": "^0.8.4", "@holochain-open-dev/profiles": "^0.17.3", diff --git a/ui/src/elements/how-agent-list.ts b/ui/src/elements/how-agent-list.ts index a3ddd2f..db7a771 100644 --- a/ui/src/elements/how-agent-list.ts +++ b/ui/src/elements/how-agent-list.ts @@ -6,7 +6,7 @@ import {ScopedElementsMixin} from "@open-wc/scoped-elements"; import { AgentPubKeyB64 } from "@holochain/client"; import { HowStore } from "../how.store"; import { howContext } from "../types"; -import { consume } from '@lit-labs/context'; +import { consume } from '@lit/context'; import { Profile, ProfilesStore, profilesStoreContext } from "@holochain-open-dev/profiles"; import { StoreSubscriber } from "@holochain-open-dev/stores"; import { decodeHashFromBase64 } from "@holochain/client"; diff --git a/ui/src/elements/how-controller.ts b/ui/src/elements/how-controller.ts index 6d19b08..7d5cd09 100644 --- a/ui/src/elements/how-controller.ts +++ b/ui/src/elements/how-controller.ts @@ -17,6 +17,11 @@ import { AsyncReadable, AsyncStatus, StoreSubscriber } from '@holochain-open-dev import { aliveImage } from "../images"; import '@shoelace-style/shoelace/dist/components/dialog/dialog.js'; import '@shoelace-style/shoelace/dist/components/button/button.js'; +import "@shoelace-style/shoelace/dist/components/dropdown/dropdown.js"; +import "@shoelace-style/shoelace/dist/components/menu-item/menu-item.js"; +import "@shoelace-style/shoelace/dist/components/menu/menu.js"; +import SlDropdown from '@shoelace-style/shoelace/dist/components/dropdown/dropdown.js'; + import SlDialog from '@shoelace-style/shoelace/dist/components/dialog/dialog.js'; import sanitize from "sanitize-filename"; @@ -32,7 +37,7 @@ import { Profile, } from "@holochain-open-dev/profiles"; import {EntryHashB64, encodeHashToBase64} from "@holochain/client"; -import { consume } from '@lit-labs/context'; +import { consume } from '@lit/context'; import { HowMyProfileDialog } from "./how-my-profile-dialog"; import { EntryRecord } from "@holochain-open-dev/utils"; //import { HowSettings } from "./how-settings"; @@ -79,6 +84,11 @@ export class HowController extends ScopedElementsMixin(LitElement) { private _document!: HowDocument; @query('#settings') private _settings!: SlDialog; + @query('#reparent') + private _reparentDialog!: SlDialog; + @state() _reparentingToUnitHash: EntryHashB64 | undefined + @query('#units-menu') + private _unitsMenu!: SlDropdown; @state() _currentUnitEh = ""; @state() _currentDocumentEh = ""; @@ -339,6 +349,23 @@ export class HowController extends ScopedElementsMixin(LitElement) { } } + async doReparent() { + if (this._reparentingToUnitHash) { + const newParent = this._units.value[this._reparentingToUnitHash].path() + const path = this._units.value[this._currentUnitEh].path() + console.log("Move ", path, "->", newParent) + await this._store.reparent(path, newParent) + } + // cleanup + this._reparentDialog.hide() + this._reparentingToUnitHash = undefined + } + + async handleReparent(event: any) { + await this._store.pullUnits() + this._reparentDialog.show() + } + async doExport() { const rawTree = await this._store.pullTree() await this.pullAllDocs("", rawTree) @@ -510,6 +537,7 @@ export class HowController extends ScopedElementsMixin(LitElement) { @select-document=${(e:any)=>this.selectDocumentVersion(e.detail.hash, e.detail.readOnly)} @select-node=${(e: any)=>{const hash = this._unitsPath.value[e.detail]; this.handleUnitSelect(hash)}} @add-child=${this.handleAddChild} + @reparent=${this.handleReparent} />` const document = this._currentDocumentEh ? html`{await this.doExport()}}>Export + + + { + e.stopPropagation() + this._unitsMenu.show() + }} + > + ${this._reparentingToUnitHash ? this._units.value[this._reparentingToUnitHash].path() : "Select new parent"} + + + this._unitsMenu.hide()} + @click=${(e:any)=>e.stopPropagation()} + @sl-select=${(e:any)=>{ + console.log("SELECTED:", e.detail.item.value) + this._reparentingToUnitHash = e.detail.item.value + this._unitsMenu.hide() + }}> + ${ + Object.entries(this._units.value).map(([key, unit]) => html` + + ${unit.path() == "" ? "" : unit.path()} + + `) + } + + + {await this.doReparent()}}>Do it! + +
+
How ${this._currentUnitEh ? ` - ${this._units.value[this._currentUnitEh].shortName}` : ''}
diff --git a/ui/src/elements/how-tree.ts b/ui/src/elements/how-tree.ts index 92da511..30b54c6 100644 --- a/ui/src/elements/how-tree.ts +++ b/ui/src/elements/how-tree.ts @@ -14,7 +14,7 @@ import { import { HowNode } from "./how-node"; import { EntryHashB64, encodeHashToBase64 } from "@holochain/client"; //import {Button, Dialog, TextField, Fab, Slider} from "@scoped-elements/material-web"; -import { consume } from '@lit-labs/context'; +import { consume } from '@lit/context'; /** * @element how-tree diff --git a/ui/src/elements/how-unit-dialog.ts b/ui/src/elements/how-unit-dialog.ts index 6f17a7e..6b98b76 100644 --- a/ui/src/elements/how-unit-dialog.ts +++ b/ui/src/elements/how-unit-dialog.ts @@ -16,7 +16,7 @@ import { } from "@scoped-elements/material-web"; import '@holochain-open-dev/profiles/dist/elements/search-agent.js'; import { StoreSubscriber } from '@holochain-open-dev/stores'; -import { consume } from '@lit-labs/context'; +import { consume } from '@lit/context'; const PROCESS_TYPES = ['define', 'refine', 'align'] as const; type ProcessType = typeof PROCESS_TYPES[number]; diff --git a/ui/src/elements/how-unit.ts b/ui/src/elements/how-unit.ts index 4b8d970..b03558a 100644 --- a/ui/src/elements/how-unit.ts +++ b/ui/src/elements/how-unit.ts @@ -17,7 +17,7 @@ import { import { Action, EntryHashB64, encodeHashToBase64 } from "@holochain/client"; import { InfoItem } from "./info-item"; import { HowConfirm } from "./how-confirm"; -import { consume } from '@lit-labs/context'; +import { consume } from '@lit/context'; import { Profile, ProfilesStore, profilesStoreContext } from "@holochain-open-dev/profiles"; const getCurrentStateName = (unit:Unit, documentState:string ): string => { @@ -171,6 +171,11 @@ export class HowUnit extends ScopedElementsMixin(LitElement) { .info=${"add child"} .button=${"plus"}> + this.dispatchEvent(new CustomEvent('reparent', { detail: this.currentUnitEh, bubbles: true, composed: true }))} + .info=${"reparent"} + .button=${"reparent"}> +
`) if (updated) { diff --git a/ui/src/elements/svg-button.ts b/ui/src/elements/svg-button.ts index 89d0ee9..340c438 100644 --- a/ui/src/elements/svg-button.ts +++ b/ui/src/elements/svg-button.ts @@ -8,6 +8,26 @@ import { action_destroyer } from "svelte/internal"; const SVG = { + reparent: ` + + + + + + + + +`, plus: ``, move: ` diff --git a/ui/src/holochain-app.ts b/ui/src/holochain-app.ts index 081aafe..7a6a40e 100644 --- a/ui/src/holochain-app.ts +++ b/ui/src/holochain-app.ts @@ -17,7 +17,7 @@ import { AppAgentClient, AppAgentWebsocket, } from '@holochain/client'; -import { provide } from '@lit-labs/context'; +import { provide } from '@lit/context'; import { LitElement, css, html } from 'lit'; import { AsyncStatus, StoreSubscriber } from '@holochain-open-dev/stores'; import { customElement, property, state } from 'lit/decorators.js'; diff --git a/ui/src/how.service.ts b/ui/src/how.service.ts index c126914..9919b58 100644 --- a/ui/src/how.service.ts +++ b/ui/src/how.service.ts @@ -53,6 +53,11 @@ export class HowService { let tree:RustTree = await this.callZome('get_tree', null); return tree.tree } + + async reparent(path: string, newParent: string): Promise { + this.callZome('reparent', {path,newParent}); + } + async notify(signal: HowSignal, folks: Array): Promise { return this.callZome('notify', {signal, folks}); } diff --git a/ui/src/how.store.ts b/ui/src/how.store.ts index 6a38891..66dca64 100644 --- a/ui/src/how.store.ts +++ b/ui/src/how.store.ts @@ -449,4 +449,8 @@ export class HowStore { count } } + + async reparent(path: string, newParent: string): Promise { + this.service.reparent(path,newParent); + } } diff --git a/ui/src/types.ts b/ui/src/types.ts index ec58075..eda2569 100644 --- a/ui/src/types.ts +++ b/ui/src/types.ts @@ -1,7 +1,7 @@ // TODO: add globally available interfaces for your elements import { ActionHash, ActionHashed, EntryHash, Record, Timestamp, EntryHashB64, AgentPubKeyB64, encodeHashToBase64 } from "@holochain/client"; -import { createContext } from "@lit-labs/context"; +import { createContext } from "@lit/context"; import { Control } from "./controls"; import { HowStore } from "./how.store";