Skip to content

Commit

Permalink
added edit unit and moved reparenting there
Browse files Browse the repository at this point in the history
  • Loading branch information
zippy committed Jan 3, 2024
1 parent d559b93 commit 23d1144
Show file tree
Hide file tree
Showing 14 changed files with 630 additions and 255 deletions.
100 changes: 67 additions & 33 deletions dnas/how/zomes/coordinator/how/src/unit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use how_integrity::{Unit, EntryTypes, LinkTypes};
use crate::document::{update_document, UpdateDocumentInput, _update_document};
use crate::error::*;
//use crate::signals::*;
use crate::tree::{UnitInfo, _get_tree, tree_path, _get_path_tree, tree_path_to_str};
use crate::tree::{UnitInfo, _get_tree, tree_path, _get_path_tree, tree_path_to_str, PathContent, Node};

pub fn get_units_path() -> Path {
Path::from("units")
Expand Down Expand Up @@ -198,62 +198,96 @@ pub fn advance_state(input: AdvanceStateInput) -> ExternResult<EntryHashB64> {
return Ok(new_doc_hash);
}

pub fn reparent_node(node: Node<PathContent>, from: String, to: String)-> ExternResult<()> {
let units = node.val.units.clone();
let current_path = node.val.path;//.clone();
for unit in units {
let documents: Vec<HoloHash<holo_hash::hash_type::Entry>> = node.val.documents.clone();

let (new_unit_output, new_unit) = reparent_unit(&unit, from.clone(), to.clone())?;
for doc in documents {
reparent_document(unit.hash.clone(), new_unit_output.info.hash.clone(), &new_unit, doc, current_path.clone(), to.clone())?;
}
}
Ok(())
}

#[derive(Clone, Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct ReparentInput {
pub path: String,
pub new_parent: String,
pub struct UpdateUnitInput {
pub hash: EntryHash,
pub state: String,
pub unit: Unit,
}
#[hdk_extern]
pub fn reparent(input: ReparentInput) -> ExternResult<()> {
if input.new_parent.starts_with(&input.path) {
return Err(wasm_error!(WasmErrorInner::Guest(String::from("Can't reparent to child"))));
pub fn update_unit(input: UpdateUnitInput) -> ExternResult<UnitOutput> {
let record = get(input.hash.clone(), GetOptions::default())?
.ok_or(wasm_error!(WasmErrorInner::Guest(String::from("Unit not found"))))?;
let old_action_hash = record.action_address().clone();
let old_unit: Unit = record
.entry()
.to_app_option().map_err(|err| wasm_error!(err))?
.ok_or(wasm_error!(WasmErrorInner::Guest(String::from("Malformed unit"))))?;

let old_tree_paths = old_unit.tree_paths();
let new_unit_output = _update_unit(input.hash.clone(), old_action_hash, old_tree_paths.clone(), &input.unit, &input.state)?;

let old_path = old_unit.path_str()?;
let new_path = input.unit.path_str()?;
let new_parent = input.unit.parents[0].clone();
let sub_tree = _get_path_tree(old_tree_paths[0].clone())?;
let root = sub_tree.tree[0].clone();
for doc in root.val.documents {
reparent_document(input.hash.clone(), new_unit_output.info.hash.clone(), &input.unit, doc, old_path.clone(), new_parent.clone())?;
}
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<HoloHash<holo_hash::hash_type::Entry>> = 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())?;
}
let reparenting = new_path != old_path || old_unit.path_abbreviation != input.unit.path_abbreviation;

if reparenting && sub_tree.tree.len() > 1 {
for node in sub_tree.tree.into_iter().skip(1) {
reparent_node(node, old_path.clone(), new_path.clone())?;
}
}
Ok(())
};
Ok(new_unit_output)
}

pub fn update_unit(hash: ActionHash, unit: &Unit) -> ExternResult<EntryHash> {
let _action_hash = update_entry(hash, unit)?;
let hash = hash_entry(unit)?;
Ok(hash)
pub fn _update_unit(hash: EntryHash, action_hash: ActionHash, paths: Vec<Path>, new_unit: &Unit, state: &str) -> ExternResult<UnitOutput> {
delete_unit_links(hash.clone(), paths)?;
let new_action_hash = update_entry(action_hash, new_unit)?;
let new_unit_hash = hash_entry(new_unit)?;
create_unit_links(new_unit_hash.clone(), new_unit.tree_paths(), state, &new_unit.version, new_unit.flags_str())?;
let maybe_record = get(new_action_hash, GetOptions::default())?;
let record = maybe_record.ok_or(wasm_error!(WasmErrorInner::Guest(String::from(
"Could not get the record created just now"
))))?;

Ok(UnitOutput {
info: UnitInfo {
hash: new_unit_hash,
state: state.into(),
version: new_unit.version.clone(),
flags: String::from(new_unit.flags_str()),
},
record,
})
}

pub fn reparent_unit(unit_info: &UnitInfo, from: String, to: String) -> ExternResult<(EntryHash, Unit)> {
pub fn reparent_unit(unit_info: &UnitInfo, from: String, to: String) -> ExternResult<(UnitOutput, 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())?;

let old_paths = 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, unit.flags_str())?;
let unit_output = _update_unit(unit_info.hash.clone(),record.action_address().clone(), old_paths, &unit, &unit_info.state)?;

Ok((new_unit_hash,unit))
Ok((unit_output,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<()> {
Expand Down
4 changes: 2 additions & 2 deletions tests/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ try {
let rootUnit = {
parents: [], // full paths to parent nodes (remember it's a DAG)
shortName: "Holochain Community Standards",
version: "vidx0",
version: "vidx:0",
pathAbbreviation: "", // max 10 char
stewards: [], // people who can change this document
processes: [["soc_proto.procs.define","petition"]], // state-machine definition
Expand Down Expand Up @@ -79,7 +79,7 @@ try {
let unit1 = {
parents: ["hc_system.conductor.api"], // full paths to parent nodes (remember it's a DAG)
shortName: "app API",
version: "vidx1",
version: "vidx:1",
pathAbbreviation: "app", // max 10 char
stewards: [], // people who can change this document
processes: [["soc_proto.procs.define","petition"]], // state-machine definition
Expand Down
90 changes: 19 additions & 71 deletions ui/src/elements/how-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { HowTree } from "./how-tree";
import { initialTreeHolochain } from "../initHolochain";
import { initialTreeSimple } from "../initSimple";
import { HowUnitDialog } from "./how-unit-dialog";
import { HowUnitDialogEdit } from "./how-unit-dialog-edit";
import { ScopedElementsMixin } from "@open-wc/scoped-elements";
import {HowDocument } from "./how-document";
import { AsyncReadable, AsyncStatus, StoreSubscriber } from '@holochain-open-dev/stores';
Expand Down Expand Up @@ -91,6 +92,11 @@ export class HowController extends ScopedElementsMixin(LitElement) {
@query('#units-menu')
private _unitsMenu!: SlDropdown;

@query('#unit-dialog')
private _unitDialogElem!: HowUnitDialog;
@query('#unit-dialog-edit')
private _editUnitDialogElem!: HowUnitDialogEdit;

@state() _currentUnitEh = "";
@state() _currentDocumentEh = "";
@state() _documentReadOnly = false;
Expand Down Expand Up @@ -186,14 +192,6 @@ export class HowController extends ScopedElementsMixin(LitElement) {
return this.shadowRoot!.getElementById("how-unit") as HowUnit;
}

async openUnitDialog(parent?: any) {
this.unitDialogElem.open(parent);
}

get unitDialogElem() : HowUnitDialog {
return this.shadowRoot!.getElementById("unit-dialog") as HowUnitDialog;
}

private async handleUnitSelect(unitEh: EntryHashB64): Promise<void> {
if (this._units.value[unitEh]) {
this._currentUnitEh = unitEh;
Expand Down Expand Up @@ -226,8 +224,13 @@ export class HowController extends ScopedElementsMixin(LitElement) {
}

handleAddChild(event: any) {
const parentEh = event.detail
this._unitDialogElem.open(parentEh)
}

handleEditUnit(event: any) {
const unitEh = event.detail
this.openUnitDialog(unitEh)
this._editUnitDialogElem.open(unitEh)
}

private isTreeType() : boolean {
Expand All @@ -247,6 +250,8 @@ export class HowController extends ScopedElementsMixin(LitElement) {
}
async handleUnitUpdated(e:any) {
await this._store.pullTree()
await this._store.pullUnits()

}
selectDocumentVersion(hash: EntryHashB64, readOnly: boolean) {
this._currentDocumentEh = hash
Expand Down Expand Up @@ -350,23 +355,6 @@ 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)
Expand Down Expand Up @@ -538,7 +526,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}
@edit=${this.handleEditUnit}
/>`
const document = this._currentDocumentEh ?
html`<how-document id="document"
Expand All @@ -555,50 +543,6 @@ export class HowController extends ScopedElementsMixin(LitElement) {
<sl-button
@click=${async ()=>{await this.doExport()}}>Export</sl-button>
</sl-dialog>
${this._currentUnitEh ? html`
<sl-dialog id="reparent" label="Reparent">
<sl-dropdown id="units-menu">
<sl-button slot="trigger"
@click=${(e:any)=>{
e.stopPropagation()
this._unitsMenu.show()
}}
>
${this._reparentingToUnitHash ? this._units.value[this._reparentingToUnitHash].path() : "Select new parent"}
</sl-button>
<sl-menu style="max-width: 100px;"
@mouseleave=${()=> this._unitsMenu.hide()}
@click=${(e:any)=>e.stopPropagation()}
@sl-select=${(e:any)=>{
this._reparentingToUnitHash = e.detail.item.value
this._unitsMenu.hide()
}}>
${
Object.entries(this._units.value).filter(([_,unit])=>{
const currentUnit = this._units.value[this._currentUnitEh]
const currentPath = currentUnit.path()
const unitPath = unit.path()
let current_path_parent = ""
if (currentUnit) {
const p = currentPath.split(".")
p.pop()
current_path_parent = p.join(".")
}
return !unitPath.startsWith(currentPath) && (unitPath != current_path_parent)
}).map(([key, unit]) => html`
<sl-menu-item value=${key}>
${unit.path() == "" ? "<Root>" : unit.path()}
</sl-menu-item>
`)
}
</sl-menu>
</sl-dropdown>
<sl-button
@click=${async ()=>{await this.doReparent()}}>Do it!</sl-button>
</sl-dialog>
` : ""}
<div>
<div id="top-bar" class="row">
Expand All @@ -618,6 +562,9 @@ export class HowController extends ScopedElementsMixin(LitElement) {
<how-unit-dialog id="unit-dialog"
@unit-added=${(e:any)=>{this.handleNodeSelected(e); this.refresh();}}>
</how-unit-dialog>
<how-unit-dialog-edit id="unit-dialog-edit"
>
</how-unit-dialog-edit>
</div>
`;
Expand All @@ -634,6 +581,7 @@ export class HowController extends ScopedElementsMixin(LitElement) {
"mwc-icon-button": IconButton,
"mwc-button": Button,
"how-unit-dialog" : HowUnitDialog,
"how-unit-dialog-edit" : HowUnitDialogEdit,
"how-unit": HowUnit,
"how-tree": HowTree,
"how-document": HowDocument,
Expand Down
2 changes: 1 addition & 1 deletion ui/src/elements/how-unit-details.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {sharedStyles} from "../sharedStyles";
import { consume } from '@lit/context';
import {ScopedElementsMixin} from "@open-wc/scoped-elements";
import {HowStore} from "../how.store";
import {Unit, howContext, Dictionary, Node} from "../types";
import {howContext} from "../types";
import {
Button,
Dialog,
Expand Down
Loading

0 comments on commit 23d1144

Please sign in to comment.