fix odlux config app 60/140360/1 master
authorMichael Dürre <michael.duerre@highstreet-technologies.com>
Mon, 3 Mar 2025 15:53:52 +0000 (16:53 +0100)
committerMichael Dürre <michael.duerre@highstreet-technologies.com>
Mon, 3 Mar 2025 15:54:04 +0000 (16:54 +0100)
fixed augment resolving order

Issue-ID: CCSDK-4094
Change-Id: I03d17f7a76266370df2201b2667a2e10b8fa93dd
Signed-off-by: Michael Dürre <michael.duerre@highstreet-technologies.com>
sdnr/wt-odlux/odlux/apps/configurationApp/src/models/uiModels.ts
sdnr/wt-odlux/odlux/apps/configurationApp/src/views/configurationApplication.tsx
sdnr/wt-odlux/odlux/apps/configurationApp/src/yang/yangParser.ts
sdnr/wt-odlux/odlux/framework/pom.xml
sdnr/wt-odlux/odlux/framework/src2/main/resources/version.json
sdnr/wt-odlux/odlux/odlux.properties

index c839f1c..c9f5e80 100644 (file)
@@ -209,7 +209,7 @@ export const isViewElementEmpty = (viewElement: ViewElement): viewElement is Vie
   return viewElement && viewElement.uiType === 'empty';
 };
 
-export const ResolveFunction = Symbol('IsResolved');
+export const ResolveFunction = Symbol('ResolveFunction');
 
 export type ViewSpecification = {
   id: string;
@@ -219,6 +219,7 @@ export type ViewSpecification = {
   parentView?: string;
   language: string;
   ifFeature?: string;
+  augmentations?: string[];
   when?: WhenAST;
   uses?: (string[]) & { [ResolveFunction]?: (parent: string) => void };
   elements: { [name: string]: ViewElement };
index c8a518b..6280950 100644 (file)
@@ -939,7 +939,6 @@ class ConfigurationApplicationComponent extends React.Component<ConfigurationApp
   }
 
   render() {
-    console.log('ConfigurationApplication.render()', this.props);
     return this.props.collectingData || !this.state.viewData
       ? this.renderCollectingData()
       : this.props.listSpecification
index 10f12dd..ec242db 100644 (file)
@@ -490,6 +490,34 @@ export class YangParser {
     return module;
   }
 
+  private calculateExecutionOrder(moduleName: string, visited: Set<string> = new Set()): number {
+    if (visited.has(moduleName)) {
+      return 0;
+    }
+    visited.add(moduleName);
+
+    const module = this.modules[moduleName];
+    const augments = module?.augments || {};
+    const augmentPaths = Object.keys(augments);
+
+    if (augmentPaths.length === 0) {
+      module.executionOrder = 0;
+      return 0;
+    }
+
+    const orders = augmentPaths.map((path) => {
+      const pathParts = path.split('/');
+      const lastPart = pathParts[pathParts.length - 1];
+      const [ns] = lastPart.split(':');
+      const baseModuleOrder = this.calculateExecutionOrder(ns, visited);
+      return baseModuleOrder + 1;
+    });
+
+    const maxOrder = Math.max(...orders);
+    module.executionOrder = maxOrder;
+    return maxOrder;
+  }
+
   public postProcess() {
     // process all type refs
     this._typeRefToResolve.forEach(cb => {
@@ -497,26 +525,28 @@ export class YangParser {
         console.warn(error.message);
       }
     });
-    /**
-     * This is to fix the issue for sequential execution of modules based on their child and parent relationship
-     * We are sorting the module object based on their augment status
-     */
-    Object.keys(this.modules)
-      .map(elem => {
-        if (this.modules[elem].augments && Object.keys(this.modules[elem].augments).length > 0) {
-          const { augments, ..._rest } = this.modules[elem];
-          const partsOfKeys = Object.keys(augments).map((key) => (key.split('/').length - 1));
-          this.modules[elem].executionOrder = Math.max(...partsOfKeys);
-        } else {
-          this.modules[elem].executionOrder = 0;
-        }
-      });
 
-    // process all augmentations / sort by namespace changes to ensure proper order 
-    Object.keys(this.modules).sort((a, b) => this.modules[a].executionOrder! - this.modules[b].executionOrder!).forEach(modKey => {
-      const module = this.modules[modKey];
+    // process all groupings
+    this._groupingsToResolve.filter(vs => vs.uses && vs.uses[ResolveFunction]).forEach(vs => {
+      try { vs.uses![ResolveFunction] !== undefined && vs.uses![ResolveFunction]!('|'); } catch (error) {
+        console.warn(`Error resolving: [${vs.name}] [${error.message}]`);
+      }
+    });
+
+    // process all augmentations
+    Object.keys(this.modules).forEach((moduleName) => {
+      this.calculateExecutionOrder(moduleName);
+    });
+
+    const orderedModules = Object.values(this.modules)
+      .filter((m) => m.executionOrder)
+      .sort((a, b) => {
+        return a.executionOrder! - b.executionOrder!;
+    });
+
+    orderedModules.forEach((module) => {
       const augmentKeysWithCounter = Object.keys(module.augments).map((key) => {
-        const pathParts = splitVPath(key, /(?:(?:([^\/\:]+):)?([^\/]+))/g);  // 1 = opt: namespace / 2 = property 
+        const pathParts = splitVPath(key, /(?:(?:([^\/\:]+):)?([^\/]+))/g); // 1 = opt: namespace / 2 = property
         let nameSpaceChangeCounter = 0;
         let currentNS = module.name; // init namespace
         pathParts.forEach(([ns, _]) => {
@@ -531,40 +561,96 @@ export class YangParser {
         };
       });
 
-      const augmentKeys = augmentKeysWithCounter
-        .sort((a, b) => a.nameSpaceChangeCounter > b.nameSpaceChangeCounter ? 1 : a.nameSpaceChangeCounter === b.nameSpaceChangeCounter ? 0 : -1)
-        .map((a) => a.key);
-
-      augmentKeys.forEach(augKey => {
-        const augments = module.augments[augKey];
-        const viewSpec = this.resolveView(augKey);
-        if (!viewSpec) console.warn(`Could not find view to augment [${augKey}] in [${module.name}].`);
-        if (augments && viewSpec) {
-          augments.forEach(augment => Object.keys(augment.elements).forEach(key => {
-            const elm = augment.elements[key];
-            
-            const when = elm.when && augment.when
-              ? {
-                type: WhenTokenType.AND,
-                left: elm.when,
-                right: augment.when,
-              }
-              : elm.when || augment.when;
-            
-            const ifFeature = elm.ifFeature
-              ? `(${augment.ifFeature}) and (${elm.ifFeature})`
-              : augment.ifFeature;
-            
-            viewSpec.elements[key] = {
-              ...augment.elements[key],
-              when,
-              ifFeature,
-            };
-          }));
+      const augmentKeys = augmentKeysWithCounter.sort((a, b) => (a.nameSpaceChangeCounter > b.nameSpaceChangeCounter ? 1 : a.nameSpaceChangeCounter === b.nameSpaceChangeCounter ? 0 : -1)).map((a) => a.key);
+
+      augmentKeys.forEach((augKey) => {
+        const viewToAugment = this.resolveView(augKey);
+        const augmentations = module.augments[augKey];
+
+        if (!viewToAugment) {
+          console.warn(`Could not find view to augment [${augKey}] from [${module.name}].`);
+          return;
+        }
+
+        if (augmentations && viewToAugment) {
+          augmentations.forEach(({ id }) => {
+            viewToAugment.augmentations = viewToAugment.augmentations || [];
+            viewToAugment.augmentations.push(id);
+          });
         }
       });
     });
 
+    // build a map of views with all their augmentation level
+    const viewsWithNestedAugmentations = new Map<ViewSpecification, number>();
+
+    // helper function to get maximum augmentation depth
+    const calculateAugmentationDepth = (view: ViewSpecification): number => {
+      // Return cached value if already calculated
+      if (viewsWithNestedAugmentations.has(view)) {
+        return viewsWithNestedAugmentations.get(view)!;
+      }
+
+      // Base case: no augmentations
+      if (!view.augmentations || view.augmentations.length === 0) {
+        viewsWithNestedAugmentations.set(view, 0);
+        return 0;
+      }
+
+      // Get depths of all child augmentations
+      let maxDepth = 0;
+      for (const augId of view.augmentations) {
+        const augView = this.views[+augId];
+        for (const nestedAugId in augView.elements || {}) {
+          const nestedAug = augView.elements[nestedAugId];
+          if (isViewElementObjectOrList(nestedAug)) {
+            const nestedView = this.views[+nestedAug.viewId];
+            maxDepth = nestedView ? Math.max(maxDepth, calculateAugmentationDepth(nestedView)) : maxDepth;
+          }
+        }
+      }
+
+      // Add 1 for current level and cache result
+      const totalDepth = maxDepth + 1;
+      viewsWithNestedAugmentations.set(view, totalDepth);
+      return totalDepth;
+    };
+
+    // process views from lowest to highest augmentation depth
+    const viewEntries = Object.entries(this.views.filter((v) => v.augmentations && v.augmentations.length > 0))
+      .map(([, view]) => view)
+      .sort((a, b) => calculateAugmentationDepth(a) - calculateAugmentationDepth(b));
+
+    for (const view of viewEntries) {
+      if (!view.augmentations || view.augmentations.length === 0) continue;
+
+      for (const augId of view.augmentations) {
+        const augmentation = this.views[+augId];
+
+        // merge elements from augmentation into main view
+        Object.keys(augmentation.elements).forEach((key) => {
+          const elm = augmentation.elements[key];
+
+          const when =
+            elm.when && augmentation.when
+              ? {
+                  type: WhenTokenType.AND,
+                  left: elm.when,
+                  right: augmentation.when,
+                }
+              : elm.when || augmentation.when;
+
+          const ifFeature = elm.ifFeature ? `(${augmentation.ifFeature}) and (${elm.ifFeature})` : augmentation.ifFeature;
+
+          view.elements[key] = {
+            ...augmentation.elements[key],
+            when,
+            ifFeature,
+          };
+        });
+      }
+    }
+    
     // process Identities
     const traverseIdentity = (identities: Identity[]) => {
       const result: Identity[] = [];
@@ -614,13 +700,6 @@ export class YangParser {
       }
     });
 
-    // process all groupings
-    this._groupingsToResolve.filter(vs => vs.uses && vs.uses[ResolveFunction]).forEach(vs => {
-      try { vs.uses![ResolveFunction] !== undefined && vs.uses![ResolveFunction]!('|'); } catch (error) {
-        console.warn(`Error resolving: [${vs.name}] [${error.message}]`);
-      }
-    });
-
     const knownViews: ViewSpecification[] = [];
     // resolve readOnly
     const resolveReadOnly = (view: ViewSpecification, parentConfig: boolean) => {
@@ -1561,6 +1640,29 @@ export class YangParser {
     return [element, resultPathParts.slice(0, -1).map(p => `${moduleName !== p.ns ? `${moduleName = p.ns}:` : ''}${p.property}${p.ind || ''}`).join('/')];
   }
 
+  
+  private resolveViewElement(name: string, referenceView: ViewSpecification): ViewElement | null {
+    let element: ViewElement | null = null;
+    element = referenceView.elements[name];
+
+    if (element) {
+      return element;
+    }
+
+    const augmentViewIds = referenceView.augmentations;
+    if (augmentViewIds) {
+      for (let i = 0; i < augmentViewIds.length; ++i) {
+        const augmentView = this._views[+augmentViewIds[i]];
+        if (augmentView) {
+          element = this.resolveViewElement(name, augmentView);
+          if (element) break;
+        }
+      }
+    }
+    return element;
+  }
+
+
   private resolveView(vPath: string) {
     const vPathParser = /(?:(?:([^\/\[\]\:]+):)?([^\/\[\]]+)(\[[^\]]+\])?)/g; // 1 = opt: namespace / 2 = property / 3 = opt: indexPath
     let element: ViewElement | null = null;
@@ -1572,16 +1674,17 @@ export class YangParser {
       if (partMatch) {
         if (element === null) {
           moduleName = partMatch[1]!;
-          const rootModule = this._modules[moduleName];
-          if (!rootModule) return null;
-          element = rootModule.elements[`${moduleName}:${partMatch[2]!}`];
+          view = Object.values(this.views).find((v) => v.parentView === '0' && v.ns === moduleName) || null;
+          if (view) {
+            element = this.resolveViewElement(`${moduleName}:${partMatch[2]!}`, view);
+          }
         } else if (isViewElementObjectOrList(element)) {
           view = this._views[+element.viewId];
           if (moduleName !== partMatch[1]) {
             moduleName = partMatch[1];
-            element = view.elements[`${moduleName}:${partMatch[2]}`];
+            element = this.resolveViewElement(`${moduleName}:${partMatch[2]}`, view);
           } else {
-            element = view.elements[partMatch[2]];
+            element = this.resolveViewElement(partMatch[2], view);
           }
         } else {
           return null;
index bffbc04..eaba5d4 100644 (file)
@@ -39,7 +39,7 @@
     <properties>
         <buildtime>${maven.build.timestamp}</buildtime>
         <distversion>ONAP Frankfurt (Neon, mdsal ${odl.mdsal.version})</distversion>
-        <buildno>172.b89e2c2b(23/10/04)</buildno>
+        <buildno>179.f46d0ef0(25/03/03)</buildno>
         <odlux.version>ONAP SDN-R | ONF Wireless for ${distversion} - Build: ${buildtime} ${buildno} ${project.version}</odlux.version>
     </properties>
 
index 1d9af90..91bd11c 100644 (file)
@@ -9,11 +9,9 @@
         "faultApp":"##odlux.apps.faultApp.buildno##",
         "helpApp":"##odlux.apps.helpApp.buildno##",
         "inventoryApp":"##odlux.apps.inventoryApp.buildno##",
-        "linkCalculationApp":"##odlux.apps.linkCalculationApp.buildno##",
         "maintenanceApp":"##odlux.apps.maintenanceApp.buildno##",
         "mediatorApp":"##odlux.apps.mediatorApp.buildno##",
-        "networkMapApp":"##odlux.apps.networkMapApp.buildno##",
         "permanceHistoryApp":"##odlux.apps.permanceHistoryApp.buildno##"
-    
+
     }
 }
\ No newline at end of file
index c4424ac..05f3146 100644 (file)
@@ -1,14 +1,10 @@
 odlux.framework.buildno=172.b89e2c2b(23/10/04)
-odlux.apps.configurationApp.buildno=172.b89e2c2b(23/10/04)
+odlux.apps.configurationApp.buildno=179.f46d0ef0(25/03/03)
 odlux.apps.connectApp.buildno=172.b89e2c2b(23/10/04)
 odlux.apps.eventLogApp.buildno=172.b89e2c2b(23/10/04)
 odlux.apps.faultApp.buildno=172.b89e2c2b(23/10/04)
 odlux.apps.helpApp.buildno=172.b89e2c2b(23/10/04)
 odlux.apps.inventoryApp.buildno=172.b89e2c2b(23/10/04)
-odlux.apps.linkCalculationApp.buildno=171.5e3c222(22/09/30)
 odlux.apps.maintenanceApp.buildno=172.b89e2c2b(23/10/04)
 odlux.apps.mediatorApp.buildno=172.b89e2c2b(23/10/04)
-odlux.apps.networkMapApp.buildno=172.b89e2c2b(23/10/04)
-odlux.apps.lineOfSightApp.buildno=168.38fd458(22/09/16)
 odlux.apps.permanceHistoryApp.buildno=81.1c38886(20/12/04)
-odlux.apps.siteManagerApp=164.e02f116(22/08/12)