If statement & PopUp window in React

In summary: Left: '55%' }} /> Yes </label> } position="right center" > <div> <h3>Why</h3> <label>
  • #36
pbuk said:
Well I'd be inclined to flatten the tree in the response into an object with the id as the key:
JavaScript:
{
  'id-1234': {
    title: '...',
    children: [
      'id-2345',
      'id-9876',
    ],
  },
  'id-2345': {
    // ...
  },
  // ...
}
which will make it much easier to use, but otherwise, yes.

I haven't understood what you mean. Could you explain that further to me?
 
Technology news on Phys.org
  • #37
Do you mean how to store the tree in a redux tree or what do you mean by the above?
 
  • #38
mathmari said:
I haven't understood what you mean. Could you explain that further to me?
Well here is the beginning of the response:
JavaScript:
[
  {
    "tree_structure": [
      {
        "TypeDefinition": "Namespace",
        "IndexName": "0:Objects",
        "URI": "http://opcfoundation.org/UA/",
        "Nodes": [
          {
            "DisplayName": "Objects",
            "Attributes": [
              {
                "NodeId": "i=85",
                "NodeClass": "Object",
                "BrowseName": "Objects",
                "DisplayName": "Objects",
                "Description": null,
                "WriteMask": null,
                "UserWriteMask": null,
                "EventNotifier": null
              }
            ],
            "Nodes": [
              {
                "DisplayName": "Server",
                "Attributes": [
                  {
                    "NodeId": "i=2253",
                    "NodeClass": "Object",
                    "BrowseName": "Server",
                    "DisplayName": "Server",
                    "Description": null,
                    "WriteMask": null,
                    "UserWriteMask": null,
                    "EventNotifier": ["SubscribeToEvents"]
                  }
                ],
                "Nodes": [
                  {
                    "DisplayName": "ServerStatus",
                    "Attributes": [
                      {
                        "NodeId": "i=2256",
                        "NodeClass": "Variable",
                        "BrowseName": "ServerStatus",
                        "DisplayName": "ServerStatus",
                        "Description": null,
                        "WriteMask": null,
                        "UserWriteMask": null,
                        "Value": "ServerStatusDataType(StartTime=datetime.datetime(2022, 9, 27, 7, 45, 53, 181000), CurrentTime=datetime.datetime(2022, 9, 27, 14, 57, 5, 827000), State=<ServerState.Running: 0>, BuildInfo_=BuildInfo(ProductUri='urn:prosysopc.com:OPCUA:SimulationServer', ManufacturerName='Prosys OPC Ltd.', ProductName='SimulationServer@DESKTOP-VN3GQ4Q', SoftwareVersion='5.3.0', BuildNumber='64', BuildDate=datetime.datetime(1970, 1, 1, 0, 0)), SecondsTillShutdown=0, ShutdownReason=LocalizedText(Locale='', Text=''))",
                        "DataType": "ExtensionObject",
                        "ValueRank": "Scalar",
                        "AccessLevel": ["CurrentRead"],
                        "UserAccessLevel": ["CurrentRead"],
                        "MinimumSamplingInterval": 1000.0,
                        "Historizing": false
                      }
                    ],
Let's say you want to display the minumum sampling interval for the node with id "i=2256": this is not going to be easy. If instead you parse this tree into a flat structure:
JavaScript:
{
  "tree_structure": {
    "TypeDefinition": "Namespace",
    "IndexName": "0:Objects",
    "URI": "http://opcfoundation.org/UA/",
    // Note the change from an array to a POJO.
    "Nodes": {
      "i=85" : {
        "DisplayName": "Objects",
        "Attributes": [
          {
            "NodeId": "i=85",
            "NodeClass": "Object",
            "BrowseName": "Objects",
            "DisplayName": "Objects",
            "Description": null,
            "WriteMask": null,
            "UserWriteMask": null,
            "EventNotifier": null
          },
        ],
        parent: null,
        children: [
          "i=2253",
        ],
      },

      "i-2253": {
        "DisplayName": "Server",
        "Attributes": [
          {
            "NodeId": "i=2253",
            "NodeClass": "Object",
            "BrowseName": "Server",
            "DisplayName": "Server",
            "Description": null,
            "WriteMask": null,
            "UserWriteMask": null,
            "EventNotifier": ["SubscribeToEvents"]
          }
        ],
        parent: "i=85",
        children: [
          "i=2256",
        ],
      },

      "i=2256": {
        "DisplayName": "ServerStatus",
        "Attributes": [
          {
            "NodeId": "i=2256",
            "NodeClass": "Variable",
            "BrowseName": "ServerStatus",
            "DisplayName": "ServerStatus",
            "Description": null,
            "WriteMask": null,
            "UserWriteMask": null,
            "Value": "ServerStatusDataType(StartTime=datetime.datetime(2022, 9, 27, 7, 45, 53, 181000), CurrentTime=datetime.datetime(2022, 9, 27, 14, 57, 5, 827000), State=<ServerState.Running: 0>, BuildInfo_=BuildInfo(ProductUri='urn:prosysopc.com:OPCUA:SimulationServer', ManufacturerName='Prosys OPC Ltd.', ProductName='SimulationServer@DESKTOP-VN3GQ4Q', SoftwareVersion='5.3.0', BuildNumber='64', BuildDate=datetime.datetime(1970, 1, 1, 0, 0)), SecondsTillShutdown=0, ShutdownReason=LocalizedText(Locale='', Text=''))",
            "DataType": "ExtensionObject",
            "ValueRank": "Scalar",
            "AccessLevel": ["CurrentRead"],
            "UserAccessLevel": ["CurrentRead"],
            "MinimumSamplingInterval": 1000.0,
            "Historizing": false
          }
        ],
        parent: "i=2253",
        children: [
          // ...
        ],
      },
      // More nodes.
it's going to be much easier, it's just data.tree_structure.Nodes['i=2253'].Attributes[0].MinimumSamplingInterval
 
  • Like
Likes mathmari
  • #39
And using the redux store this is possible?
 
  • #40
For the beginning I tried to do that with a non elegant way, to get all data by for loops, I used 3 for loops. I am not reallt sure if I print it correctly with the <TreeView>, could you take a look at it ?

JavaScript:
    const [dataObj, setDataObj] = useState([]);
    
    useEffect(() => {
        fetch('https://giant-db-connection.onrender.com/opc_ua_tree/')
            .then((res) => res.json())
            .then((data) => {
                setDataObj(data[0]['tree_structure'][0].Nodes[0]);
                console.log(data[0]['tree_structure'][0].Nodes[0].DisplayName);
                <TreeView
                    aria-label="file system navigator"
                    sx={{ flexGrow: 1, overflowY: 'auto' }}
                    style={{ height: '34vh', width: '100%' }}
                >
                    <TreeItem nodeId={data[0]['tree_structure'][0].Nodes[0].DisplayName} label={data[0]['tree_structure'][0].Nodes[0].DisplayName}>
                        for (let i = 0; i < data[0]['tree_structure'][0].Nodes[0].Nodes.length; i++) {
                            console.log(data[0]['tree_structure'][0].Nodes[0].Nodes[i].DisplayName);
                            <TreeItem nodeId={data[0]['tree_structure'][0].Nodes[0].Nodes[i].DisplayName} label={data[0]['tree_structure'][0].Nodes[0].Nodes[i].DisplayName}>
                                for (let j = 0; j < data[0]['tree_structure'][0].Nodes[0].Nodes[i].Nodes.length; j++) {
                                    console.log(data[0]['tree_structure'][0].Nodes[0].Nodes[i].Nodes[j].DisplayName);
                                    <TreeItem nodeId={data[0]['tree_structure'][0].Nodes[0].Nodes[i].Nodes[j].DisplayName} label={data[0]['tree_structure'][0].Nodes[0].Nodes[i].Nodes[j].DisplayName} />
                                }
                            </TreeItem>
                        }
                    </TreeItem>
                </TreeView>
            });
    }, []);
🤔
 
Last edited:
  • #41
Or isn't it possible to use a for-loop inside the TreeView? Do we maybe have to use an extra function for that? 🤔
 
  • #42
mathmari said:
For the beginning I tried to do that with a non elegant way, to get all data by for loops, I used 3 for loops.
That won't work. You need to build it recursively, something like this:
JavaScript:
  const tree = {
    server: null,
    treeId: null,
    rootNodeId: null,
    nodes: {},
  };

  const loadTree = async () => {
    const data = await fetchTree();
    tree.server = data[0].server;
    tree.treeId = data[0].tree_id;
    tree.nodes = {};
    const { id } = parseNode(data[0].tree_structure[0].Nodes[0], tree.nodes);
    tree.rootNodeId = id;
  };

  const parseNode = (rawNode, nodes) => {
    // Recursively parse the child nodes, adding to this nodes children.
    const children = [];
    (rawNode.Nodes ?? []).forEach((item) => {
      const { id } = parseNode(item, nodes);
      children.push(id);
    });

    // Create this node.
    const node = {
      id: rawNode.Attributes[0].NodeId,
      title: rawNode.DisplayName,
      children,
      attributes: rawNode.Attributes,
    };

    // Save this node to the dictionary.
    nodes[id] = node;

    // Return the node so the caller can get the id.
    return node;
  };
 
  • Like
Likes mathmari
  • #43
pbuk said:
That won't work. You need to build it recursively, something like this:
JavaScript:
  const tree = {
    server: null,
    treeId: null,
    rootNodeId: null,
    nodes: {},
  };

  const loadTree = async () => {
    const data = await fetchTree();
    tree.server = data[0].server;
    tree.treeId = data[0].tree_id;
    tree.nodes = {};
    const { id } = parseNode(data[0].tree_structure[0].Nodes[0], tree.nodes);
    tree.rootNodeId = id;
  };

  const parseNode = (rawNode, nodes) => {
    // Recursively parse the child nodes, adding to this nodes children.
    const children = [];
    (rawNode.Nodes ?? []).forEach((item) => {
      const { id } = parseNode(item, nodes);
      children.push(id);
    });

    // Create this node.
    const node = {
      id: rawNode.Attributes[0].NodeId,
      title: rawNode.DisplayName,
      children,
      attributes: rawNode.Attributes,
    };

    // Save this node to the dictionary.
    nodes[id] = node;

    // Return the node so the caller can get the id.
    return node;
  };

When we initialize the tree, the keys are the one of the first level of the endpoint ? I mean the following :

1667205785313.png
Could you explain to me the function loadTree ? According to the picture I loaded above we have :

tree.server = data[0].server = 41
tree.treeId = data[0].tree_id = 19

Or not? Could you explain to me the following part?

tree.nodes = {};
const { id } = parseNode(data[0].tree_structure[0].Nodes[0], tree.nodes);
tree.rootNodeId = id;With the function parseNode do we parse through all children nodes?

🤔
 
  • #44
Is the idea to buid the tree that we get from the API again from scratch? 🤔
 
  • #45
mathmari said:
Is the idea to buid the tree that we get from the API again from scratch? 🤔
Yes. Working with a nested tree is practically impossible so this is standard practice.

Rather than explain every element I have created a basic but fully working application in plain JavaScript with no dependencies. You can see the code as a GitHub gist and you can see it working below. Note that sometimes the API does not respond first time, I guess this is due to some limitations on the, possibly free, cloud service.

The code doesn't have many comments in, that is deliberate so you can work through it and see how it all works, and then convert it to React.js using your component libraries of choice, and if you wish Redux (although if all you are going to do is display the data you fetch there is no need to use Redux for this).

 
Last edited:
  • #46
mathmari said:
Is the idea to buid the tree that we get from the API again from scratch? 🤔
Of course if whoever had designed the API had done a better job we wouldn't have to do this.

There are some other odd things about the API response, for instance why is Attributes an array with a single element? Why do the id's not have a regular form: many start with "i=" but some look like e.g. "ns=1;s=79f4049c-8266-4758-9c5a-0013e39273d7/0:SessionDiagnostics/0:ActualSessionTimeout"? Why do some nodes exist at more than one point in the tree (hopefully with the same values) e.g. i=2341?

These are rhetorical questions, I think I'm done here.
 

Similar threads

Replies
10
Views
1K
Replies
16
Views
4K
Replies
4
Views
3K
Replies
4
Views
6K
Back
Top