-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* sarda-devesh/main: Fixed deps Added single example of updated feedback component
- Loading branch information
Showing
8 changed files
with
648 additions
and
247 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -63,7 +63,9 @@ | |
"prettier": {}, | ||
"dependencies": { | ||
"@babel/preset-react": "^7.18.6", | ||
"poplar-annotation": "^2.0.3" | ||
"poplar-annotation": "^2.0.3", | ||
"react-arborist": "^3.4.0", | ||
"react-text-annotate-blend": "^1.2.0" | ||
}, | ||
"packageManager": "[email protected]", | ||
"dependenciesMeta": { | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,276 @@ | ||
import React, { useEffect, useRef, useState } from 'react'; | ||
import example_data from './tree_example.json'; | ||
import {StatefulBlendProps, StatefulBlend} from './TextVisualizer'; | ||
import { NodeApi, Tree, TreeApi } from "react-arborist"; | ||
import Node from './Node'; | ||
import {Entity, Result, TreeData} from './types'; | ||
import { TextAnnotateBlend, AnnotateBlendTag } from "react-text-annotate-blend"; | ||
|
||
|
||
function process_entity(paragraph : string, entity : Entity, depth: number) : TreeData { | ||
// Record its children | ||
let curr_children : TreeData[] = []; | ||
if(entity.children) { | ||
for(var child of entity.children) { | ||
curr_children.push(process_entity(paragraph, child, depth + 1)); | ||
} | ||
} | ||
|
||
// Create the current node | ||
let entity_tag = "" + depth; | ||
return { | ||
id : entity_tag + "_" + entity.txt_range[0][0] + "_" + entity.txt_range[0][1], | ||
name: paragraph.substring(entity.txt_range[0][0], entity.txt_range[0][1]), | ||
children : curr_children | ||
} | ||
} | ||
|
||
function formatForVisualization(initial_tree : Result) : [string, TreeData[]] { | ||
let paragraph : string = initial_tree.text; | ||
let tree_entities : TreeData[] = []; | ||
if(initial_tree.strats) { | ||
for(var curr_strat of initial_tree.strats) { | ||
tree_entities.push(process_entity(paragraph, curr_strat, 0)); | ||
} | ||
} | ||
|
||
let root : TreeData = { | ||
id : "root", | ||
name : "All entities", | ||
children : tree_entities | ||
}; | ||
|
||
return [paragraph, [root]]; | ||
} | ||
|
||
function update_tree(current_node: TreeData, nodes_set: Set<string>) { | ||
// Update the children | ||
let new_children : TreeData[] = []; | ||
for(var curr_child of current_node.children) { | ||
if(nodes_set.has(curr_child.id)) { | ||
// We want to keep this child | ||
new_children.push(curr_child); | ||
nodes_set.delete(curr_child.id); | ||
} else { | ||
// We don't want to keep this node so make its grand children its child | ||
for(var grand_child of curr_child.children) { | ||
nodes_set.delete(grand_child.id); | ||
new_children.push(grand_child); | ||
} | ||
} | ||
} | ||
|
||
// Call update on each of the children | ||
for(var curr_new_child of new_children) { | ||
update_tree(curr_new_child, nodes_set); | ||
} | ||
|
||
// Update the children of this node | ||
current_node.children = new_children; | ||
} | ||
|
||
function perform_reset(node : TreeData, depth: number) { | ||
// Reset the depth | ||
let old_id_parts = node.id.split("_"); | ||
let new_id = depth.toString() + "_" + old_id_parts[1] + "_" + old_id_parts[2]; | ||
node.id = new_id; | ||
|
||
for(var child of node.children) { | ||
perform_reset(child, depth + 1); | ||
} | ||
} | ||
|
||
function removeNodes(current_node: TreeData, nodes_to_remove: Set<string>, removed_nodes : TreeData[]) { | ||
let new_children : TreeData[] = []; | ||
for(var curr_child of current_node.children) { | ||
if(nodes_to_remove.has(curr_child.id)) { | ||
// Record that we removed this node | ||
removed_nodes.push(curr_child); | ||
} else { | ||
// Keep this child | ||
new_children.push(curr_child); | ||
} | ||
} | ||
|
||
// Process the children | ||
for(var curr_new_child of new_children) { | ||
removeNodes(curr_new_child, nodes_to_remove, removed_nodes); | ||
} | ||
|
||
// Update the children for this node | ||
current_node.children = new_children; | ||
} | ||
|
||
function addInChild(current_node : TreeData, target_node: string, removed_nodes: TreeData[]) { | ||
if(current_node.id.valueOf() == target_node.valueOf()) { | ||
// Add in the children to the target node | ||
for(var node_to_add of removed_nodes) { | ||
current_node.children.push(node_to_add); | ||
} | ||
} else { | ||
// This node is not the target node so its a child | ||
for(var curr_child of current_node.children) { | ||
addInChild(curr_child, target_node, removed_nodes); | ||
} | ||
} | ||
|
||
} | ||
|
||
function recordNode(node: TreeData, nodes_set : Set<string>) { | ||
nodes_set.add(node.id); | ||
for(var child of node.children) { | ||
recordNode(child, nodes_set); | ||
} | ||
} | ||
|
||
export function FeedbackWrap({data}) { | ||
let input_data : Result = data; | ||
let [current_text, tree_entities] : [string, TreeData[]] = formatForVisualization(input_data); | ||
let [current_tree, setTree] = useState(tree_entities); | ||
let no_nodes : string[] = []; | ||
let [nodes_to_show, setNodesToShow] = useState(no_nodes); | ||
|
||
// Processing update from the text visualization | ||
let process_update = (nodes: string[]) => { | ||
let nodes_set = new Set<string>(nodes); | ||
let old_root = current_tree[0]; | ||
let new_root = JSON.parse(JSON.stringify(old_root)); | ||
console.log("Old root of", old_root); | ||
|
||
// Update the tree | ||
console.log("Nodes to keep", nodes); | ||
update_tree(new_root, nodes_set); | ||
console.log("New root of", new_root); | ||
|
||
// Add the remaining children as | ||
nodes_set.forEach((node) => { | ||
// Get the id details | ||
let node_parts = node.split("_"); | ||
let start_idx : number = parseInt(node_parts[1]); | ||
let end_idx : number = parseInt(node_parts[2]); | ||
|
||
// Create the new node | ||
let new_id : string = "0_" + start_idx.toString() + "_" + end_idx.toString(); | ||
let name : string = current_text.substring(start_idx, end_idx); | ||
new_root.children.push({ | ||
id : new_id, | ||
name : name, | ||
children: [] | ||
}) | ||
}); | ||
|
||
// Reset the level of all of nodes | ||
for(var root_child of new_root.children) { | ||
perform_reset(root_child, 0); | ||
} | ||
|
||
setTree([new_root]); | ||
}; | ||
|
||
// If the user rename the tree | ||
const treeRef = useRef(); | ||
const onMove = ({ dragIds, parentId, index } : any) => { | ||
// Cast the input data | ||
let input_children_ids : string[] = dragIds; | ||
let input_parent_id : string = parentId; | ||
let input_index : number = index; | ||
|
||
// Create the new root | ||
let old_root = current_tree[0]; | ||
let new_root = JSON.parse(JSON.stringify(old_root)); | ||
|
||
// Remove the children from there location | ||
let nodes_to_remove : Set<string> = new Set<string>(input_children_ids); | ||
let removed_nodes : TreeData[] = []; | ||
let updated_children: TreeData[] = []; | ||
for(var root_child of new_root.children) { | ||
if(nodes_to_remove.has(root_child.id)) { | ||
// Don't record this is a root child | ||
removed_nodes.push(root_child); | ||
} else { | ||
// Record it as a child | ||
removeNodes(root_child, nodes_to_remove, removed_nodes); | ||
updated_children.push(root_child); | ||
} | ||
} | ||
new_root.children = updated_children; | ||
|
||
if(input_parent_id == "root") { | ||
// Add in the children to the root | ||
for(var node_to_add of removed_nodes) { | ||
new_root.children.push(node_to_add); | ||
} | ||
} else { | ||
// Add in to the target node | ||
for(var root_child of new_root.children) { | ||
addInChild(root_child, input_parent_id, removed_nodes); | ||
} | ||
} | ||
|
||
// Reset the level of all of nodes | ||
for(var root_child of new_root.children) { | ||
perform_reset(root_child, 0); | ||
} | ||
setTree([new_root]); | ||
}; | ||
|
||
const onDelete = ({ ids } : any) => { | ||
let delete_ids : string[] = ids; | ||
|
||
// Create the new root | ||
let old_root = current_tree[0]; | ||
let new_root = JSON.parse(JSON.stringify(old_root)); | ||
|
||
// Remove the children from there location | ||
let nodes_to_remove : Set<string> = new Set<string>(delete_ids); | ||
let removed_nodes : TreeData[] = []; | ||
let updated_children: TreeData[] = []; | ||
for(var root_child of new_root.children) { | ||
if(nodes_to_remove.has(root_child.id)) { | ||
// Don't record this is a root child | ||
removed_nodes.push(root_child); | ||
} else { | ||
// Record it as a child | ||
removeNodes(root_child, nodes_to_remove, removed_nodes); | ||
updated_children.push(root_child); | ||
} | ||
} | ||
new_root.children = updated_children; | ||
|
||
// Reset the level of all of nodes | ||
for(var root_child of new_root.children) { | ||
perform_reset(root_child, 0); | ||
} | ||
setTree([new_root]); | ||
}; | ||
|
||
const onSelect = (nodes : NodeApi<TreeData>[]) => { | ||
let nodes_to_show = new Set<string>(); | ||
for(var curr_node of nodes) { | ||
recordNode(curr_node.data, nodes_to_show); | ||
} | ||
|
||
setNodesToShow(Array.from(nodes_to_show)); | ||
}; | ||
|
||
return ( | ||
<> | ||
<div style={{display:"grid", gridTemplateColumns:"1fr 1fr"}}> | ||
<div> | ||
<p> | ||
Click on a entity to see its type as well as the type of its children. | ||
You can also drag and drop entities up and down the heirachy, thus changing their type. | ||
</p> | ||
<Tree data={current_tree} ref={treeRef} onMove={onMove} onDelete={onDelete} onSelect={onSelect}> | ||
{Node} | ||
</Tree> | ||
</div> | ||
|
||
<StatefulBlend formatted_text={current_text} tree_data={current_tree[0].children} update_nodes={process_update} nodes_to_show={nodes_to_show} /> | ||
</div> | ||
</> | ||
); | ||
|
||
} | ||
|
||
export default FeedbackWrap; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import { AiFillFolder, AiFillFile } from "react-icons/ai"; | ||
import { MdArrowRight, MdArrowDropDown, MdEdit } from "react-icons/md"; | ||
import { RxCross2 } from "react-icons/rx"; | ||
import { NodeApi, Tree, TreeApi } from "react-arborist"; | ||
import React from "react"; | ||
import {Entity, Child, Result, TreeData} from './types'; | ||
|
||
function isSelected(search_node : TreeData, tree_node: TreeData) { | ||
if(search_node.id == tree_node.id) { | ||
return true; | ||
} | ||
|
||
for(var child of tree_node.children) { | ||
if(isSelected(search_node, child)) { | ||
return true; | ||
} | ||
} | ||
|
||
return false; | ||
} | ||
|
||
function isNodeSelected(node : NodeApi<TreeData>, tree: TreeApi<TreeData>) { | ||
for(var selected_node of tree.selectedNodes) { | ||
if(isSelected(node.data, selected_node.data)) { | ||
return true; | ||
} | ||
} | ||
|
||
return false; | ||
} | ||
|
||
type COLOR_TYPE = { | ||
[key: string]: string; | ||
0: string; | ||
1: string; | ||
2: string; | ||
}; | ||
|
||
const COLORS: COLOR_TYPE = { | ||
0: "rgb(179, 245, 66)", | ||
1: "#42f5f5", | ||
2: "#4b46cd", | ||
}; | ||
|
||
const Node = ({ node, style, dragHandle, tree } : any) => { | ||
let selected : boolean = isNodeSelected(node, tree); | ||
let node_level : string = node.data.id.split("_")[0]; | ||
let nameStyle = selected ? { backgroundColor: COLORS[node_level] } : {}; | ||
|
||
return ( | ||
<div style={{ ...style, ...nameStyle }} ref={dragHandle}> | ||
{"🍁"} | ||
{node.data.name} | ||
</div> | ||
); | ||
}; | ||
|
||
export default Node; |
Oops, something went wrong.