From e688af39adc2b794e95a00fae71b27fc99974628 Mon Sep 17 00:00:00 2001 From: Maximilian Wesener Date: Tue, 3 Dec 2024 07:38:55 +0100 Subject: [PATCH 1/6] chore: add ai assist phase 2 solution --- icc-irs-challenges/ai-assistent-phase2.md | 225 +++++++++++++++++----- 1 file changed, 180 insertions(+), 45 deletions(-) diff --git a/icc-irs-challenges/ai-assistent-phase2.md b/icc-irs-challenges/ai-assistent-phase2.md index d4efb42b..4c10256c 100644 --- a/icc-irs-challenges/ai-assistent-phase2.md +++ b/icc-irs-challenges/ai-assistent-phase2.md @@ -36,30 +36,192 @@ Our goal is to progressively enhance the frontend. In this second phase of the w #### Input Phase 2 - **Goal**: Enhance the frontend from Phase 1 to: - - Read and visualize specific information from submodel data (e.g., `catenaXId`, `payload`, etc.). - - Visualize relationships between different data models using a graph. - - The `globalAssetId` and the `catenaXId` are the same, providing a direct link between these identifiers across - different components - - Child Relationships: - The children of a `SingleLevelBomAsBuilt` are represented as complete `SerialPart` - entities within the `submodels`. Each child is fully modeled to provide detailed information. - - Parent and Child Connections: In the payload of `SingleLevelBomAsBuilt`, the `catenaXId` refers to a`SerialPart`. - This `SerialPart` serves as the **parent part**, positioned above the `SingleLevelBomAsBuilt` in the graph - hierarchy. - - The `SingleLevelBomAsBuilt` acts as the **relationship node** connecting two `SerialParts`. It is positioned - **between** the parent `SerialPart` and its children. - - The children of the `SingleLevelBomAsBuilt` are positioned **below** the corresponding `SerialPart` in the - graph. This visualization clearly delineates parent-child relationships and highlights the intermediary role of - `SingleLevelBomAsBuilt`. - - By adhering to these rules, the graph accurately represents the hierarchical and relational structure of the data, - making it easier to interpret the connections between `SerialParts` and their relationships. + - Visualize a graph using mermaid. + - First parent node is the globalAssetId provided in the job.globalAssetId. Use this to search through shells[] shell.payload.globalAssetId and find the corresponding shell object. + - Take the shell object to find the corresponding submodeldescriptior parentShell.payload.submodelDescriptors object only for urn:samm:io.catenax.single_level_bom_as_built:3.0.0#SingleLevelBomAsBuilt + - Use the id of the submodeldescriptior and search for the submodel which corresponds to it submodels[?].identification === submodelDescriptor `semanticId.keys[0].value` + - The element will be a node in the graph. + - Do that as long as you find elements. + - The names of the nodes should be the catenaxid + - A Parent-Child relation should be oriented from top to bottom (TD) + - If a child of the first parent has other children it should act as parent to its children. + - If there are multiple children to one parent, then the children should be next to each other horizontally. +- +- Here is some additional information to let you understand the models: +- - The `globalAssetId` and the `catenaXId` are the same, providing a direct link between these identifiers across + different components +- Child Relationships: - The children of a `SingleLevelBomAsBuilt` are represented as complete `SerialPart` + entities within the `submodels`. Each child is fully modeled to provide detailed information. +- Parent and Child Connections: In the payload of `SingleLevelBomAsBuilt`, the `catenaXId` refers to a`SerialPart`. + This `SerialPart` serves as the **parent part**, positioned above the `SingleLevelBomAsBuilt` in the graph + hierarchy. +- The `SingleLevelBomAsBuilt` acts as the **relationship node** connecting two `SerialParts`. It is positioned + **between** the parent `SerialPart` and its children. +- The children of the `SingleLevelBomAsBuilt` are positioned **below** the corresponding `SerialPart` in the + graph. This visualization clearly delineates parent-child relationships and highlights the intermediary role of + `SingleLevelBomAsBuilt`. - Use exactly this mermaid version: - - Initialize mermaid like this: + - Initialize mermaid like this: ```js mermaid.initialize({ startOnLoad: false, theme: 'default' }); ``` + - Use the provided html / js to achieve the expected behaviour +```html + + + + + + IRS API Frontend with Graph + + + + +

IRS API Job Registration

+ + + +

+ + +

+ + + + + + +

Response:

+

+
+

Graph Visualization:

+
+ + + + +``` + +- Present the result and gather feedback. + - **Acceptance Criteria**: - All criteria from Phase 1 are met. - Specific submodel data fields are extracted and visualized. @@ -93,34 +255,7 @@ Our goal is to progressively enhance the frontend. In this second phase of the w - Request confirmation if all files have been provided, if not ask for the content. ### Step 4: Develop Solution for Phase 2 -- Extend the frontend from Phase 1, which was provided in Step 2 by the user to: - - Extract fields (e.g., `job.globalAssetId`, `job.state`, `job.parameter.bpn`, `shells[?].payload.globalAssetId`, - `shells[?].payload.submodelDescriptors.semanticId.keys[0].value`, `shells[?].payload.submodelDescriptors.id`, - `submodels[?].identification`, `submodels[?].payload.catenaXId`, `submodels[?].payload.localIdentifiers`) from the - job detail response. - - Visualize these fields and relationships with a mermaid graph. Embed the graph in the html and visualize it with mermaid. Use Mermaid version 11 - - The names of the nodes should be the catenaxid - - The requested globalAssetId (catenaXId) is the beginning node. This is found with `data.job.globalAssetId` from the response. - - A Parent-Child relation should be oriented from top to bottom (TD) - - If there are multiple children to one parent, then the children should be next to each other horizontally. - - If a child of the first parent has other children it should act as parent to its children. - - Find the shells[] array from `data.shells[]` - - From shells[] array - - Extract fields from shells (`payload.globalAssetId`, `payload.specificAssetIds[]`, - `payload.submodelDescriptors[]`) - - From array submodelDescriptors[] get the submodelDescriptor where `semanticId.keys[0].value` is equal to `urn:samm:io.catenax.single_level_bom_as_built:3.0.0#SingleLevelBomAsBuilt` - - Extract field from submodelDescriptor: `id` - - From array specificAssetIds[] get the name value pairs where `name` is one of `manufacturerId`, - `manufacturerPartId`, `digitalTwinType` if they are present. - - Attach fields from shells to shells graph node - - Find the submodels[] array from `data.submodels[]` - - From submodels[] array - - Get submodel with `identification` equal to the `id` from the submodelDescriptor - - Attach fields submodels graph edge (`submodels[?].payload.catenaXId`, - `submodels[?].payload.childItems[?].catenaXId`,`submodels[?].payload.childItems[?].businessPartner`) -- Ensure JSON data is now structured and visually accessible in HTML. -- Present the result and gather feedback. - +- Extend the frontend from Phase 1, which was provided in Step 2 by the user to create a graph as described in the "Input Phase 2" - **Next Step**: Inform participants they can enhance the graph and styling creatively. Encourage questions about styling. From 819121156373af91a974e61bb6c019a69bdb0f76 Mon Sep 17 00:00:00 2001 From: Maximilian Wesener Date: Tue, 3 Dec 2024 09:09:44 +0100 Subject: [PATCH 2/6] chore: add ai assist phase 2 solution --- icc-irs-challenges/ai-assistent-phase2.md | 250 +++++++++++++--------- 1 file changed, 147 insertions(+), 103 deletions(-) diff --git a/icc-irs-challenges/ai-assistent-phase2.md b/icc-irs-challenges/ai-assistent-phase2.md index 4c10256c..c99ac132 100644 --- a/icc-irs-challenges/ai-assistent-phase2.md +++ b/icc-irs-challenges/ai-assistent-phase2.md @@ -37,16 +37,18 @@ Our goal is to progressively enhance the frontend. In this second phase of the w - **Goal**: Enhance the frontend from Phase 1 to: - Visualize a graph using mermaid. - - First parent node is the globalAssetId provided in the job.globalAssetId. Use this to search through shells[] shell.payload.globalAssetId and find the corresponding shell object. + - The graph should be placed above the json response of phase 1 + - Below the buttons for Register Job or Get Job Response + - First parent node is the globalAssetId provided in the job.globalAssetId. Use this to search through shells[] shell.payload.globalAssetId and find the corresponding shell object. - Take the shell object to find the corresponding submodeldescriptior parentShell.payload.submodelDescriptors object only for urn:samm:io.catenax.single_level_bom_as_built:3.0.0#SingleLevelBomAsBuilt - Use the id of the submodeldescriptior and search for the submodel which corresponds to it submodels[?].identification === submodelDescriptor `semanticId.keys[0].value` - - The element will be a node in the graph. + - The element will be a node in the graph. - Do that as long as you find elements. - The names of the nodes should be the catenaxid - A Parent-Child relation should be oriented from top to bottom (TD) - If a child of the first parent has other children it should act as parent to its children. - If there are multiple children to one parent, then the children should be next to each other horizontally. -- +- - Here is some additional information to let you understand the models: - - The `globalAssetId` and the `catenaXId` are the same, providing a direct link between these identifiers across different components @@ -60,6 +62,9 @@ Our goal is to progressively enhance the frontend. In this second phase of the w - The children of the `SingleLevelBomAsBuilt` are positioned **below** the corresponding `SerialPart` in the graph. This visualization clearly delineates parent-child relationships and highlights the intermediary role of `SingleLevelBomAsBuilt`. +- +- Under the graph there should be one box which acts as a display box to present detail information of a node +- The detail information will be shown if a node will be clicked. - Use exactly this mermaid version: - Initialize mermaid like this: ```js @@ -68,21 +73,21 @@ Our goal is to progressively enhance the frontend. In this second phase of the w theme: 'default' }); ``` - - Use the provided html / js to achieve the expected behaviour +- Use the provided html / js to achieve the expected behaviour ```html - - - IRS API Frontend with Graph - - + + + IRS API Frontend with Graph and Details + +

IRS API Job Registration

@@ -105,116 +110,155 @@ Our goal is to progressively enhance the frontend. In this second phase of the w

Graph Visualization:

+

Node Detail Information:

+ + @@ -245,13 +289,13 @@ Our goal is to progressively enhance the frontend. In this second phase of the w --- ### Step 2: Request current code base -- Explain the user that you need the code for the previous phase to be able to support with phase 2. +- Explain the user that you need the code for the previous phase to be able to support with phase 2. - Tell them that they also can copy multiple files at the same time in the chat -- Tell them that you only need the html, css and javascript not any libraries or something else. +- Tell them that you only need the html, css and javascript not any libraries or something else. - Also make clear that they can copy the raw content of the full file (js / html / css) -### Step 3: Request more code -- Do the same as you did in step 2. +### Step 3: Request more code +- Do the same as you did in step 2. - Request confirmation if all files have been provided, if not ask for the content. ### Step 4: Develop Solution for Phase 2 From 6dabc44544e7fcb2b88ba1df25c97be27813c29a Mon Sep 17 00:00:00 2001 From: Maximilian Wesener Date: Tue, 3 Dec 2024 11:16:53 +0100 Subject: [PATCH 3/6] chore: add ai assist phase 2 solution --- icc-irs-challenges/ai-assistent-phase2.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/icc-irs-challenges/ai-assistent-phase2.md b/icc-irs-challenges/ai-assistent-phase2.md index c99ac132..dae8e9b0 100644 --- a/icc-irs-challenges/ai-assistent-phase2.md +++ b/icc-irs-challenges/ai-assistent-phase2.md @@ -104,9 +104,6 @@ Our goal is to progressively enhance the frontend. In this second phase of the w -

Response:

-

-
 

Graph Visualization:

@@ -119,6 +116,9 @@ Our goal is to progressively enhance the frontend. In this second phase of the w

Digital Twin Type:

+

Response:

+

+
 
+  
+
+
+
+

IRS API Job Registration

+ + + +

+ + +

+ + + + + + +

Graph Visualization:

+
+ +

Node Detail Information:

+ + +

Response:

+

+
+
+
+
+
+```
 ---
 
 ## Process
@@ -66,57 +298,26 @@ Our goal is to progressively enhance the frontend. In this second phase of the w
 
 ### Step 3: Develop Solution for Phase 3
 
-- Add detailed submodel information to the graph created in Phase 2.
-- Optimize the visualization for clarity and completeness.
+- Add detailed submodel information to the detail info box below the graph from Phase 2
+- Make sure to add a new header named "Submodel" below the currently implemented: Details for Node
+- Make sure that all extracted fiels will be simply displayed with name and value do not add those attributes as varialb
 - From submodels[] array
-- In case of `aspectType`: `urn:samm:io.catenax.serial_part:3.0.0#SerialPart`
-  - Extract fields from submodels (
-  - `submodels[?].payload.localIdentifiers.partInstanceId`,
-  - `submodels[?].payload.localIdentifiers.van`, 
-  - `submodels[?].payload.localIdentifiers.manufacturerId`, 
+  - Extract fields from submodels(
+  - `submodels[?].aspectType`,
   - `submodels[?].payload.manufacturingInformation.date`, 
   - `submodels[?].payload.manufacturingInformation.country`,
-  - `submodels[?].payload.manufacturingInformation.sites.catenaXsiteId`, 
-  - `submodels[?].payload.manufacturingInformation.sites.function`,
+  - `submodels[?].payload.manufacturingInformation.sites[?].catenaXsiteId`, 
+  - `submodels[?].payload.manufacturingInformation.sites[?].function`,
   - `submodels[?].payload.partTypeInformation.manufacturerPartId`,
-  - `submodels[?].payload.partTypeInformation.partClassification.classificationDescription`,
-  - `submodels[?].payload.partTypeInformation.partClassification.classificationStandard`,
-  - `submodels[?].payload.partTypeInformation.partClassification.classificationID`,
-  - `submodels[?].payload.partTypeInformation.partClassification.classificationDescription`,
-  - `submodels[?].payload.partTypeInformation.nameAtManufacturer`,
-  - `submodels[?].payload.partTypeInformation.nameAtCustomer`)
-- In case of `aspectType`: `urn:samm:io.catenax.batch:3.0.0#Batch`
-  - Extract fields from submodels (
-  - `submodels[?].payload.localIdentifiers.batchId`,
-  - `submodels[?].payload.localIdentifiers.van`,
-  - `submodels[?].payload.localIdentifiers.manufacturerId`,
-  - `submodels[?].payload.manufacturingInformation.date`,
-  - `submodels[?].payload.manufacturingInformation.country`,
-  - `submodels[?].payload.manufacturingInformation.sites.catenaXsiteId`,
-  - `submodels[?].payload.manufacturingInformation.sites.function`,
-  - `submodels[?].payload.partTypeInformation.manufacturerPartId`,
-  - `submodels[?].payload.partTypeInformation.partClassification.classificationDescription`,
-  - `submodels[?].payload.partTypeInformation.partClassification.classificationStandard`,
-  - `submodels[?].payload.partTypeInformation.partClassification.classificationID`,
-  - `submodels[?].payload.partTypeInformation.partClassification.classificationDescription`,
-  - `submodels[?].payload.partTypeInformation.nameAtManufacturer`,
-  - `submodels[?].payload.partTypeInformation.nameAtCustomer`)
-- In case of `aspectType`: `urn:samm:io.catenax.just_in_sequence_part:3.0.0#JustInSequencePart`
-  - `submodels[?].payload.localIdentifiers.jisNumber`,
-  - `submodels[?].payload.localIdentifiers.van`,
-  - `submodels[?].payload.localIdentifiers.manufacturerId`,
-  - `submodels[?].payload.manufacturingInformation.date`,
-  - `submodels[?].payload.manufacturingInformation.country`,
-  - `submodels[?].payload.manufacturingInformation.sites.catenaXsiteId`,
-  - `submodels[?].payload.manufacturingInformation.sites.function`,
-  - `submodels[?].payload.partTypeInformation.manufacturerPartId`,
-  - `submodels[?].payload.partTypeInformation.partClassification.classificationDescription`,
-  - `submodels[?].payload.partTypeInformation.partClassification.classificationStandard`,
-  - `submodels[?].payload.partTypeInformation.partClassification.classificationID`,
-  - `submodels[?].payload.partTypeInformation.partClassification.classificationDescription`,
+  - `submodels[?].payload.partTypeInformation.partClassification[?].classificationDescription`,
+  - `submodels[?].payload.partTypeInformation.partClassification[?].classificationStandard`,
+  - `submodels[?].payload.partTypeInformation.partClassification[?].classificationID`,
+  - `submodels[?].payload.partTypeInformation.partClassification[?].classificationDescription`,
   - `submodels[?].payload.partTypeInformation.nameAtManufacturer`,
   - `submodels[?].payload.partTypeInformation.nameAtCustomer`)
 
+
+
 - Present the result and gather final feedback.
 - **Next Step**: Inform participants they can refine and style the graph creatively. Encourage questions about styling.
   Ask if they want to extend the solution further or finalize the workshop.

From 3a42ce0766085dbedd7e81addf57ff0f54b89f5f Mon Sep 17 00:00:00 2001
From: Maximilian Wesener 
Date: Tue, 3 Dec 2024 11:23:05 +0100
Subject: [PATCH 5/6] chore: add final solution

---
 icc-irs-challenges/index.html | 247 +++++++++++++++++++++++++++++-----
 1 file changed, 216 insertions(+), 31 deletions(-)

diff --git a/icc-irs-challenges/index.html b/icc-irs-challenges/index.html
index 644ba019..c7aed198 100644
--- a/icc-irs-challenges/index.html
+++ b/icc-irs-challenges/index.html
@@ -1,44 +1,229 @@
-
 
 
+
 
-    
     
     
-    Frontend Workshop - Challenge 1
-    
+    IRS API Frontend with Graph and Details
 
+    
+    
+    
 
+
 
-
-

Structured Data

-
-

Graph Visualization

- +

IRS API Job Registration

+ + + +

+ + +

+ + + + + + +

Graph Visualization:

+
+ +

Node Detail Information:

+ -

Frontend Workshop: Challenge 1

- - -

+

Response:

+

+
+
+        function buildGraph(parentId) {
+            const parentShell = shells.find(shell => shell.payload.globalAssetId === parentId);
+            if (!parentShell) return;
+
+            const submodelDescriptor = parentShell.payload.submodelDescriptors.find(descriptor =>
+                descriptor.semanticId.keys[0].value === "urn:samm:io.catenax.single_level_bom_as_built:3.0.0#SingleLevelBomAsBuilt"
+            );
+
+            if (!submodelDescriptor) return;
+
+            const submodel = submodels.find(sub => sub.identification === submodelDescriptor.id);
+            if (!submodel || visited.has(parentId)) return;
+            visited.add(parentId);
+
+            graphDefinition += `${parentId}["${parentId}"]\n`;
+
+            if (submodel.aspectType === 'urn:samm:io.catenax.single_level_bom_as_built:3.0.0#SingleLevelBomAsBuilt') {
+                submodel.payload.childItems.forEach(child => {
+                    graphDefinition += `${parentId} --> ${child.catenaXId}["${child.catenaXId}"]\n`;
+                    buildGraph(child.catenaXId);
+                });
+            }
+        }
+
+        buildGraph(globalAssetId);
+
+        document.getElementById('graphContainer').innerHTML = `
${graphDefinition}
`; + mermaid.init(); + + // Add event listener to nodes for detail display + document.querySelectorAll('.mermaid').forEach((node) => { + node.addEventListener('click', (event) => { + const nodeId = event.target.textContent; + showNodeDetails(nodeId); + }); + }); + } + + function showNodeDetails(nodeId) { + if (!irsResponse || !irsResponse.shells) return; + + const shell = irsResponse.shells.find(s => s.payload.globalAssetId === nodeId); + if (!shell || !shell.payload.specificAssetIds) return; + + const specificAssets = shell.payload.specificAssetIds; + let detailsHtml = `

Details for Node: ${nodeId}

`; + + specificAssets.forEach(asset => { + const assetName = asset.name; + const assetValue = asset.value || 'N/A'; + + detailsHtml += `

${assetName}: ${assetValue}

`; + }); + + // New Submodel Details Section + const submodel = irsResponse.submodels.find(sm => sm.identification === shell.payload.submodelDescriptors[0].id); + if (submodel) { + detailsHtml += `

Submodel Details:

`; + + // Fields to display from the submodel + const fields = [ + { name: "Aspect Type", value: submodel.aspectType }, + { name: "Manufacturing Date", value: submodel.payload.manufacturingInformation?.date }, + { name: "Manufacturing Country", value: submodel.payload.manufacturingInformation?.country }, + { name: "Manufacturer Part ID", value: submodel.payload.partTypeInformation?.manufacturerPartId }, + { name: "Name at Manufacturer", value: submodel.payload.partTypeInformation?.nameAtManufacturer }, + { name: "Name at Customer", value: submodel.payload.partTypeInformation?.nameAtCustomer }, + ]; + + // Add fields for each site entry in manufacturingInformation + if (Array.isArray(submodel.payload.manufacturingInformation?.sites)) { + submodel.payload.manufacturingInformation.sites.forEach((site, index) => { + fields.push( + { name: `CatenaX Site ID ${index + 1}`, value: site.catenaXsiteId }, + { name: `Function ${index + 1}`, value: site.function } + ); + }); + } + + // Add fields for part classification + if (Array.isArray(submodel.payload.partTypeInformation?.partClassification)) { + submodel.payload.partTypeInformation.partClassification.forEach((classification, index) => { + fields.push( + { name: `Classification Description ${index + 1}`, value: classification.classificationDescription }, + { name: `Classification Standard ${index + 1}`, value: classification.classificationStandard }, + { name: `Classification ID ${index + 1}`, value: classification.classificationID } + ); + }); + } + + // Display the fields + fields.forEach(field => { + detailsHtml += `

${field.name}: ${field.value || 'N/A'}

`; + }); + } + + document.getElementById('nodeDetails').innerHTML = detailsHtml; + document.getElementById('nodeDetails').style.display = 'block'; + } + + + From 9e8ec860d6112e1516f9dc81c808ef7a4672a41e Mon Sep 17 00:00:00 2001 From: Maximilian Wesener Date: Tue, 3 Dec 2024 11:23:39 +0100 Subject: [PATCH 6/6] chore: add final solution --- icc-irs-challenges/script.js | 194 ----------------------------------- 1 file changed, 194 deletions(-) delete mode 100644 icc-irs-challenges/script.js diff --git a/icc-irs-challenges/script.js b/icc-irs-challenges/script.js deleted file mode 100644 index e090b1a6..00000000 --- a/icc-irs-challenges/script.js +++ /dev/null @@ -1,194 +0,0 @@ -/******************************************************************************** - * Copyright (c) 2024 Contributors to the Eclipse Foundation - * - * See the NOTICE file(s) distributed with this work for additional - * information regarding copyright ownership. - * - * This program and the accompanying materials are made available under the - * terms of the Apache License, Version 2.0 which is available at - * https://www.apache.org/licenses/LICENSE-2.0. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - * SPDX-License-Identifier: Apache-2.0 - ********************************************************************************/ -const registerJobButton = document.getElementById('register-job'); -const getJobDetailsButton = document.getElementById('get-job-details'); -const outputElement = document.getElementById('output'); -const structuredOutput = document.getElementById('structured-output'); -const canvas = document.getElementById('relationship-graph'); -const ctx = canvas.getContext('2d'); -let jobId = null; - -// Register Job -registerJobButton.addEventListener('click', async () => { - const response = await fetch('http://localhost:3000/api/irs/jobs', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - aspects: [ - "urn:samm:io.catenax.serial_part:3.0.0#SerialPart", - "urn:samm:io.catenax.just_in_sequence_part:3.0.0#JustInSequencePart", - "urn:samm:io.catenax.batch:3.0.0#Batch", - "urn:samm:io.catenax.single_level_bom_as_built:3.0.0#SingleLevelBomAsBuilt" - ], - key: { - globalAssetId: "", - bpn: "" - }, - collectAspects: true, - direction: "downward" - }) - }); - - const data = await response.json(); - jobId = data.id; - outputElement.textContent = `Job Registered: ${JSON.stringify(data, null, 2)}`; - getJobDetailsButton.disabled = false; -}); - -// Get Job Details -getJobDetailsButton.addEventListener('click', async () => { - if (!jobId) return; - const response = await fetch(`http://localhost:3000/api/irs/jobs/${jobId}`); - const data = await response.json(); - outputElement.textContent = `Job Details: ${JSON.stringify(data, null, 2)}`; - // Display structured data - displayStructuredData(data); - - // Draw the graph - drawGraph(data); -}); - -const displayStructuredData = (data) => { - const { job, submodels } = data; - - const html = ` -

Global Asset ID: ${job.globalAssetId}

-

State: ${job.state}

-

BPN: ${job.parameter.bpn}

-

Direction: ${job.parameter.direction}

-

Submodels:

-
    - ${submodels - .map( - (submodel) => ` -
  • - CatenaX ID: ${submodel.payload.catenaXId}
    - Local Identifiers: ${JSON.stringify( - submodel.payload.localIdentifiers, - null, - 2 - )} -
  • ` - ) - .join('')} -
- `; - structuredOutput.innerHTML = html; -}; - -// Function to draw a simple graph -const drawGraph = (data) => { - const { submodels, relationships } = data; - - // Clear the canvas - ctx.clearRect(0, 0, canvas.width, canvas.height); - - const nodePositions = {}; // Track positions for tooltips - - // Draw nodes - submodels.forEach((submodel, index) => { - const x = 100 + index * 150; - const y = canvas.height / 2; - - // Draw nodes - ctx.beginPath(); - ctx.arc(x, y, 30, 0, Math.PI * 2); - ctx.fillStyle = '#3498db'; - ctx.fill(); - ctx.stroke(); - - // Add labels - ctx.fillStyle = '#000'; - ctx.font = '12px Arial'; - ctx.fillText(submodel.payload.catenaXId, x - 30, y - 40); - - // Store node position for tooltips - nodePositions[submodel.payload.catenaXId] = { x, y, details: submodel }; - }); - - // Draw relationships - relationships.forEach((relationship) => { - const parentNode = nodePositions[relationship.catenaXId]; - const childNode = - nodePositions[relationship.linkedItem.childCatenaXId]; - - if (parentNode && childNode) { - const { x: x1, y: y1 } = parentNode; - const { x: x2, y: y2 } = childNode; - - ctx.beginPath(); - ctx.moveTo(x1, y1); - ctx.lineTo(x2, y2); - ctx.strokeStyle = '#e74c3c'; - ctx.stroke(); - - // Add relationship label - const midX = (x1 + x2) / 2; - const midY = (y1 + y2) / 2; - ctx.fillStyle = '#000'; - ctx.fillText(relationship.aspectType, midX, midY - 10); - } - }); - - // Add tooltips on hover - canvas.addEventListener('mousemove', (event) => { - const rect = canvas.getBoundingClientRect(); - const mouseX = event.clientX - rect.left; - const mouseY = event.clientY - rect.top; - - // Clear previous tooltip - ctx.clearRect(0, 0, canvas.width, canvas.height); - drawGraph(data); // Redraw the graph - - // Check if hovering over a node - Object.values(nodePositions).forEach(({ x, y, details }) => { - const distance = Math.sqrt( - Math.pow(mouseX - x, 2) + Math.pow(mouseY - y, 2) - ); - if (distance < 30) { - // Display tooltip - ctx.fillStyle = '#ffffff'; - ctx.fillRect(x + 10, y - 30, 200, 80); - ctx.strokeStyle = '#000'; - ctx.strokeRect(x + 10, y - 30, 200, 80); - - ctx.fillStyle = '#000'; - ctx.font = '10px Arial'; - ctx.fillText( - `CatenaX ID: ${details.payload.catenaXId}`, - x + 15, - y - 15 - ); - ctx.fillText( - `Part ID: ${details.payload.localIdentifiers[0]?.value || 'N/A'}`, - x + 15, - y - ); - ctx.fillText( - `Manufacturer: ${ - details.payload.partTypeInformation?.manufacturerPartId || 'N/A' - }`, - x + 15, - y + 15 - ); - } - }); - }); -}; -