Published on InterSystems Developer Community (https://community.intersystems.com)

Home > Store Mindmaps using Globals

Article
Yuri Marx Perei... · Apr 4, 2022 12m read
Open Exchange

Store Mindmaps using Globals

  

Globals are the core of the InterSystems IRIS for data persistence. It is flexible, allowing store JSON documents, relational data, object oriented data, OLAP cubes and custom data models, like Mindmaps. To see how to store, delete and get mindmap data using globals, follow these steps:

1. Clone/git pull the repo into any local directory

$ git clone https://github.com/yurimarx/global-mindmap.git

2. Open a Docker terminal in this directory and run:

$ docker-compose build

3. Run the IRIS container:

$ docker-compose up -d

4. Go to http://localhost:3000 to use the Mindmap frontend and create mindmaps like above mindmap.

 

The source code for this sample

Data to be stored (see more in: https://www.npmjs.com/package/mind-elixir):

{
  topic: 'node topic',
  id: 'bd1c24420cd2c2f5',
  style: { fontSize: '32', color: '#3298db', background: '#ecf0f1' },
  parent: null,
  tags: ['Tag'],
  icons: ['😀'],
  hyperLink: 'https://github.com/ssshooter/mind-elixir-core',
}

Pay attention to the parent property, it is used to build parent/children relationships between mindmap nodes.

Source code to store mindmap node using global

 
ClassMethod StoreMindmapNode
/// Store mindmap node
ClassMethod StoreMindmapNode() As %Status
{
    Try {
     
      Set data = {}.%FromJSON(%request.Content)
     
      Set ^mindmap(data.id) = data.id /// set mindmap key
      Set ^mindmap(data.id, "topic") = data.topic /// set topic subscript
      Set ^mindmap(data.id, "style", "fontSize") = data.style.fontSize /// set style properties subscripts
      Set ^mindmap(data.id, "style", "color") = data.style.color
      Set ^mindmap(data.id, "style", "background") = data.style.background
      Set ^mindmap(data.id, "parent") = data.parent /// store parent id subscript
      Set ^mindmap(data.id, "tags") = data.tags.%ToJSON() /// store tags subscript
      Set ^mindmap(data.id, "icons") = data.icons.%ToJSON() /// store icons subscript
      Set ^mindmap(data.id, "hyperLink") = data.hyperLink /// store hyperLink subscript
     
      Set %response.Status = 200
      Set %response.Headers("Access-Control-Allow-Origin")="*"
      Write "Saved"
      Return $$$OK
    } Catch err {
      write !, "Error name: ", ?20, err.Name,
          !, "Error code: ", ?20, err.Code,
          !, "Error location: ", ?20, err.Location,
          !, "Additional data: ", ?20, err.Data, !
      Return $$$NOTOK
  }
}

It was created a global called ^mindmap. For each mindmap property it is stored in a global subscript. The subscript key is the mindmap id property.

Source Code to Delete Mindmap node - kill the global

 
ClassMethod DeleteMindmapNode
/// Delete mindmap node
ClassMethod DeleteMindmapNode(id As %String) As %Status
{
    Try {
     
      Kill ^mindmap(id) /// delete selected mindmap node using the id (global key)
     
      Set %response.Status = 200
      Set %response.Headers("Access-Control-Allow-Origin")="*"
      Write "Deleted"
      Return $$$OK
    } Catch err {
      write !, "Error name: ", ?20, err.Name,
          !, "Error code: ", ?20, err.Code,
          !, "Error location: ", ?20, err.Location,
          !, "Additional data: ", ?20, err.Data, !
      Return $$$NOTOK
  }
}

This sample used mindmap.id to be the mindmap global key, so to delete is easy: call Kill ^mindmap(<mindmap id>)

Source code to Get all content stored - Looping globals with $ORDER

 
ClassMethod GetMindmap - return all mindmap global nodes
/// Get mindmap content
ClassMethod GetMindmap() As %Status
{
    Try {
     
      Set Nodes = []
 
      Set Key = $Order(^mindmap("")) /// get the first mindmap node stored - the root
      Set Row = 0
     
      While (Key '= "") { /// while get child mindmap nodes
        Do Nodes.%Push({}) /// create a item into result
        Set Nodes.%Get(Row).style = {}
        Set Nodes.%Get(Row).id = Key /// return the id property
        Set Nodes.%Get(Row).hyperLink = ^mindmap(Key,"hyperLink") /// return the hyperlink property
        Set Nodes.%Get(Row).icons = ^mindmap(Key,"icons") /// return icons property
        Set Nodes.%Get(Row).parent = ^mindmap(Key,"parent") /// return parent id property
        Set Nodes.%Get(Row).style.background = ^mindmap(Key,"style", "background") /// return the style properties
        Set Nodes.%Get(Row).style.color = ^mindmap(Key,"style", "color")
        Set Nodes.%Get(Row).style.fontSize = ^mindmap(Key,"style", "fontSize")
        Set Nodes.%Get(Row).tags = ^mindmap(Key,"tags") /// return tags property
        Set Nodes.%Get(Row).topic = ^mindmap(Key,"topic") /// return topic property (title mindmap node)
        Set Row = Row + 1
       
        Set Key = $Order(^mindmap(Key)) /// get the key to the next mindmap global node
      }
     
      Set %response.Status = 200
      Set %response.Headers("Access-Control-Allow-Origin")="*"
      Write Nodes.%ToJSON()
      Return $$$OK
    } Catch err {
      write !, "Error name: ", ?20, err.Name,
          !, "Error code: ", ?20, err.Code,
          !, "Error location: ", ?20, err.Location,
          !, "Additional data: ", ?20, err.Data, !
      Return $$$NOTOK
  }
}

It was used $Order(^mindmap("")) - empty "" - to get the first mindmap global ocurrence (root node). For each property value it was used ^mindmap(Key,<property name>). Finally, it was called $Order(^mindmap(Key)) to get the next ocurrence.

Frontend 

Mind-elixir and React were used for render and edit the mindmap, consuming API backend built using IRIS. See the mindmap react component:

 
Mindmap React component - consuming IRIS REST API
import React from "react";
import MindElixir, { E } from "mind-elixir";
import axios from 'axios';
 
class Mindmap extends React.Component {
 
    componentDidMount() {
 
        this.dynamicWidth = window.innerWidth;
        this.dynamicHeight = window.innerHeight;
       
        axios.get(`http://localhost:52773/global-mindmap/hasContent`)
            .then(res => {
                if (res.data == "1") {
                    axios.get(`http://localhost:52773/global-mindmap/get`)
                        .then(res2 => {
                            this.ME = new MindElixir({
                                el: "#map",
                                direction: MindElixir.LEFT,
                                data: this.renderExistentMindmap(res2.data),
                                draggable: true, // default true
                                contextMenu: true, // default true
                                toolBar: true, // default true
                                nodeMenu: true, // default true
                                keypress: true // default true
                            });
                            this.ME.bus.addListener('operation', operation => {
                                console.log(operation)
                   
                                if (operation.name == 'finishEdit' || operation.name == 'editStyle') {
                                    this.saveMindmapNode(operation.obj)
                                } else if (operation.name == 'removeNode') {
                                    this.deleteMindmapNode(operation.obj.id)
                                }
                            })
                            this.ME.init();
                        })
                   
                } else {
                    this.ME = new MindElixir({
                        el: "#map",
                        direction: MindElixir.LEFT,
                        data: MindElixir.new("New Mindmap"),
                        draggable: true, // default true
                        contextMenu: true, // default true
                        toolBar: true, // default true
                        nodeMenu: true, // default true
                        keypress: true // default true
                    });
                    this.ME.bus.addListener('operation', operation => {
                        console.log(operation)
           
                        if (operation.name == 'finishEdit' || operation.name == 'editStyle') {
                            this.saveMindmapNode(operation.obj)
                        } else if (operation.name == 'removeNode') {
                            this.deleteMindmapNode(operation.obj.id)
                        }
                    })
                    this.saveMindmapNode(this.ME.nodeData)
                    this.ME.init();
                }
 
               
            })
 
    }
 
    render() {
        return (
            <div id="map" style={{ height: window.innerHeight + 'px', width: '100%' }} />
        );
    }
 
    deleteMindmapNode(mindmapNodeId) {
        axios.delete(`http://localhost:52773/global-mindmap/delete/${mindmapNodeId}`)
            .then(res => {
                console.log(res);
                console.log(res.data);
            })
    }
 
    saveMindmapNode(node) {
 
        axios.post(`http://localhost:52773/global-mindmap/save`, {
            topic: (node.topic == undefined ? "" : node.topic),
            id: node.id,
            style: (node.style == undefined ? "" : node.style),
            parent: (node.parent == undefined ? "" : node.parent.id),
            tags: (node.tags == undefined ? [] : node.tags),
            icons: (node.icons == undefined ? [] : node.icons),
            hyperLink: (node.hyperLink == undefined ? "" : node.hyperLink)
        })
            .then(res => {
                console.log(res);
                console.log(res.data);
            })
    }
 
    renderExistentMindmap(data) {
       
        let root = data[0]
 
        let nodeData = {
            id: root.id,
            topic: root.topic,
            root: true,
            style: {
                background: root.style.background,
                color: root.style.color,
                fontSize: root.style.fontSize,
            },
            hyperLink: root.hyperLink,
            children: []
        }
 
        this.createTree(nodeData, data)
 
        return { nodeData }
    }
 
    createTree(nodeData, data) {
        for(let i = 1; i < data.length; i++) {
            if(data[i].parent == nodeData.id) {
                let newNode = {
                    id: data[i].id,
                    topic: data[i].topic,
                    root: false,
                    style: {
                        background: data[i].style.background,
                        color: data[i].style.color,
                        fontSize: data[i].style.fontSize,
                    },
                    hyperLink: data[i].hyperLink,
                    children: []
                }
                nodeData.children.push(newNode)
                this.createTree(newNode, data)
            }
        }
    }
 
   
}
 
export default Mindmap;

If you liked - vote in my app on Globals Contest. Thanks!

#Globals #InterSystems IRIS
Check the related application on InterSystems Open Exchange

Source URL:https://community.intersystems.com/post/store-mindmaps-using-globals