Merge "Widget MS startup fix and Onboarding changes"
authorSunder Tattavarada <statta@research.att.com>
Fri, 31 Jul 2020 02:45:20 +0000 (02:45 +0000)
committerGerrit Code Review <gerrit@onap.org>
Fri, 31 Jul 2020 02:45:20 +0000 (02:45 +0000)
13 files changed:
ecomp-portal-widget-ms/widget-ms/src/main/java/org/onap/portalapp/widget/controller/WidgetsCatalogController.java
ecomp-portal-widget-ms/widget-ms/src/main/java/org/onap/portalapp/widget/service/StorageService.java
ecomp-portal-widget-ms/widget-ms/src/main/java/org/onap/portalapp/widget/service/impl/StorageServiceImpl.java
ecomp-portal-widget-ms/widget-ms/src/main/java/org/onap/portalapp/widget/service/impl/WidgetCatalogServiceImpl.java
ecomp-portal-widget-ms/widget-ms/src/main/java/org/onap/portalapp/widget/utils/UnzipUtil.java
portal-FE-common/src/app/layout/components/tabbar/tabbar.component.html
portal-FE-common/src/app/pages/functional-menu/functional-menu.component.html
portal-FE-common/src/app/pages/functional-menu/functional-menu.component.ts
portal-FE-common/src/app/pages/web-analytics/web-analytics.component.scss
portal-FE-os/src/app/pages/application-onboarding/application-details-dialog/application-details-dialog.component.html
portal-FE-os/src/app/pages/application-onboarding/application-details-dialog/application-details-dialog.component.ts
portal-FE-os/src/app/pages/application-onboarding/application-onboarding.component.html
portal-FE-os/src/app/pages/application-onboarding/application-onboarding.component.ts

index 1896a4f..e6c1c0a 100644 (file)
@@ -163,13 +163,14 @@ public class WidgetsCatalogController {
                try {
                        //check the zip file structure first
                        respond = storageService.checkZipFile(file);
+                       logger.debug("Check file validity"+respond.isValid()+respond.getError());
                        if(respond.isValid()){
                                //update the widget catalog
                                WidgetCatalog newWidget = new ObjectMapper().readValue(widget, WidgetCatalog.class);
                                widgetCatalogService.updateWidgetCatalog(widgetId, newWidget);
                                logger.debug("WidgetsCatalogController.saveWidgetCatalog: updating widget with widgetId={}", widgetId);
                                //update the widget zip file
-                               storageService.update(file, newWidget, widgetId);
+                               storageService.updateJsFile(file, newWidget, widgetId);
                        }
                } catch (Exception e) {
                        logger.error("Exception occurred while performing WidgetsCatalogController.saveWidgetCatalog in widget microservices. Details:", e);
index fbd0f96..d8b5642 100644 (file)
@@ -30,5 +30,7 @@ public interface StorageService {
     
     void update(MultipartFile file, WidgetCatalog newWidget, long widgetId);
     
+    void updateJsFile(MultipartFile file, WidgetCatalog newWidget, long widgetId);
+    
        byte[] getWidgetCatalogContent(long widgetId) throws Exception;
 }
index 7a35ba4..3bb41b6 100644 (file)
@@ -73,7 +73,7 @@ public class StorageServiceImpl implements StorageService {
                Criteria criteria = session.createCriteria(WidgetFile.class);
                criteria.add(Restrictions.eq("widgetId", widgetId));
                List<WidgetFile> widgetFiles = criteria.list();
-               session.flush();
+               //session.flush();
                session.close();
                if (widgetFiles.size() > 0)
                        widgetFile = widgetFiles.get(0);
@@ -148,7 +148,7 @@ public class StorageServiceImpl implements StorageService {
                        logger.error("StorageServiceImpl.save: Failed to store file " + file.getOriginalFilename(), e);
                        throw new StorageException("Failed to store file " + file.getOriginalFilename(), e);
                }
-               saveHelper(newWidget, widgetId, map);
+               saveJsHelper(newWidget, widgetId, map);
        }
 
        @Override
@@ -167,7 +167,7 @@ public class StorageServiceImpl implements StorageService {
                        throw new StorageException("Failed to store file " + file.getName(), e);
                }
                
-               saveHelper(newWidget, widgetId, map);
+               saveJsHelper(newWidget, widgetId, map);
        }
 
        /**
@@ -259,6 +259,90 @@ public class StorageServiceImpl implements StorageService {
                                widgetId);
 
        }
+       
+       /**
+        * Helper method to UnZip File
+        * 
+        * @param file
+        */
+       private Map<String, byte[]> unZipFile(MultipartFile file) {
+               UnzipUtil unzipper = new UnzipUtil();
+               Map<String, byte[]> map;
+               File convFile;
+               try {
+                       if (file.isEmpty()) {
+                               logger.error("StorageServiceImpl.update: Failed to store empty file " + file.getOriginalFilename());
+                               throw new StorageException("Failed to store empty file " + file.getOriginalFilename());
+                       }
+                       String fileLocation = file.getOriginalFilename();
+                       logger.debug("StorageServiceImpl.update: store the widget to:" + fileLocation);
+                       convFile = new File(fileLocation);
+                       try(FileOutputStream fos = new FileOutputStream(convFile)){
+                               fos.write(file.getBytes());
+                       }
+                       map = unzipper.unzip_db(fileLocation, ".", "tempWidgets");
+                       convFile.delete();
+                       return map;
+               } catch (IOException e) {
+                       logger.error("StorageServiceImpl.update: Failed to store file " + file.getOriginalFilename(), e);
+                       throw new StorageException("StorageServiceImpl.update: Failed to store file " + file.getOriginalFilename(),
+                                       e);
+               }
+       }
+       
+       /**
+        * Helper method for saving widget file (controller.js) to ep_widget_catalog_files table in database
+        * 
+        * @param newWidget
+        * @param widgetId
+        * @param map
+        */
+       private void saveJsHelper(WidgetCatalog newWidget, long widgetId, Map<String, byte[]> map) {
+
+               logger.debug("Going to save controller.js " + newWidget);
+               WidgetFile widgetFile = new WidgetFile();
+               widgetFile.setName(newWidget.getName());
+               widgetFile.setWidgetId(widgetId);
+               final byte[] controllerLoc = map.get(WidgetConstant.WIDGET_CONTROLLER_LOCATION);
+               if (controllerLoc == null || controllerLoc.length == 0)
+                       throw new IllegalArgumentException(
+                                       "Map is missing required key " + WidgetConstant.WIDGET_CONTROLLER_LOCATION);
+               String javascript = new String(controllerLoc);
+
+               widgetFile.setController(javascript.getBytes());
+               Session session = sessionFactory.openSession();
+               session.save(widgetFile);
+               session.flush();
+               session.close();
+               logger.debug(
+                               "StorageServiceImpl.save: saved controller.js file to the database for widget {}",
+                               widgetId);
+
+       }
+       
+       @Override
+       public void updateJsFile(MultipartFile file, WidgetCatalog newWidget, long widgetId) {
+               Map<String, byte[]> map;
+               map = unZipFile(file);
+               //Get existing widget file from DB      
+               WidgetFile widgetFile = getWidgetFile(widgetId);
+               
+               String javascript = new String(map.get(WidgetConstant.WIDGET_CONTROLLER_LOCATION));
+               widgetFile.setController(javascript.getBytes());
+               Session session = sessionFactory.openSession();
+               Transaction tx = session.beginTransaction();
+               session.update(widgetFile);
+               tx.commit();
+               session.flush();
+               session.close();
+               logger.debug(
+                               "StorageServiceImpl.save: updated controller.js file to the database for widget {}",
+                               widgetId);
+       }
+       
+       
+       
+       
 
        @Override
        public void update(MultipartFile file, WidgetCatalog newWidget, long widgetId) {
@@ -424,53 +508,14 @@ public class StorageServiceImpl implements StorageService {
        public byte[] getWidgetCatalogContent(long widgetId) throws Exception {
 
                WidgetCatalog widget = widgetCatalogService.getWidgetCatalog(widgetId);
-               String namespace = "Portal" + widgetId + "Widget";
-               String controllerName = "Portal" + widgetId + "Ctrl";
-               String cssName = "portal" + widgetId + "-css-ready";
-
-               String styles = getWidgetCSS(widgetId).replaceAll(cssName, widget.getName() + "-css-ready");
                File f = File.createTempFile("temp", ".zip");
                try(ZipOutputStream out = new ZipOutputStream(new FileOutputStream(f))){
-                       ZipEntry e = new ZipEntry(widget.getName() + "/styles/styles.css");
-                       out.putNextEntry(new ZipEntry(widget.getName() + "/"));
-                       out.putNextEntry(new ZipEntry(widget.getName() + "/styles/"));
-                       out.putNextEntry(e);
-                       byte[] data = styles.getBytes();
-                       out.write(data, 0, data.length);
-       
-                       String widgetData = namespace + "=" + namespace + "||{};" + "var res = " + namespace + ".widgetData;";
-                       String javascript = getWidgetController(widgetId).replace(widgetData, "").replace(namespace + ".controller =",
-                                       "");
-       
-                       String functionHeader = javascript.substring(javascript.indexOf("function"), javascript.indexOf(")") + 1);
-                       javascript = javascript.replaceFirst(controllerName, widget.getName() + "Ctrl");
-                       String functionParam = functionHeader.substring(functionHeader.indexOf("(") + 1, functionHeader.indexOf(")"));
-                       StringBuilder injectStr = new StringBuilder().append("[");
-                       List<String> paramList = Arrays.asList(functionParam.split(","));
-                       for (int i = 0; i < paramList.size(); i++) {
-                               if (i == paramList.size() - 1)
-                                       injectStr.append("'" + paramList.get(i).trim() + "'];");
-                               else
-                                       injectStr.append("'" + paramList.get(i).trim() + "',");
-                       }
-                       javascript = javascript.replace(";" + namespace + ".controller.$inject = " + injectStr.toString(), "");
+                       String javascript = getWidgetController(widgetId);
        
-                       e = new ZipEntry(widget.getName() + "/js/controller.js");
+                       ZipEntry e = new ZipEntry(widget.getName() + "/js/controller.js");
                        out.putNextEntry(new ZipEntry(widget.getName() + "/js/"));
                        out.putNextEntry(e);
-                       data = javascript.getBytes();
-                       out.write(data, 0, data.length);
-       
-                       String html = getWidgetMarkup(widgetId).replaceFirst(controllerName, widget.getName() + "Ctrl");
-       
-                       // new
-                       // String(map.get(WidgetConstant.WIDGET_MARKUP_LOCATION)).replaceFirst(functionName,
-                       // controllerName);;
-       
-                       e = new ZipEntry(widget.getName() + "/markup/markup.html");
-                       out.putNextEntry(new ZipEntry(widget.getName() + "/markup/"));
-                       out.putNextEntry(e);
-                       data = html.getBytes();
+                       byte[] data = javascript.getBytes();
                        out.write(data, 0, data.length);
                        out.closeEntry();
                        byte[] result = Files.readAllBytes(Paths.get(f.getPath()));
index 4554ab5..d71356f 100644 (file)
@@ -148,9 +148,7 @@ public class WidgetCatalogServiceImpl implements WidgetCatalogService {
        @Override
        public WidgetCatalog getWidgetCatalog(Long widgetCatalogId) {
                Session session = sessionFactory.getCurrentSession();
-               Transaction tx = session.beginTransaction();
                WidgetCatalog widget = (WidgetCatalog) session.get(WidgetCatalog.class, widgetCatalogId);
-               tx.commit();
                logger.debug("WidgetCatalogServiceImpl.getWidgetCatalog: getting widget={}", widget);
                return widget;
        }
index f20ed1b..164a698 100644 (file)
@@ -51,8 +51,7 @@ public class UnzipUtil {
                        ZipEntry entry = zipIn.getNextEntry();
                        Map<String, byte[]> map = new HashMap<>();
        
-                       String[] requiredKeys = { WidgetConstant.WIDGET_CONTROLLER_LOCATION, WidgetConstant.WIDGET_MARKUP_LOCATION,
-                                       WidgetConstant.WIDGET_STYLE_LOCATION };
+                       String[] requiredKeys = { WidgetConstant.WIDGET_CONTROLLER_LOCATION };
                        for (String k : requiredKeys)
                                map.put(k, null);
        
index 65ccf1d..db0b6af 100644 (file)
 
   -->
 
+  <style>
+    .apps-tab {
+     position: absolute;
+     width: 100%;
+     height: 100%;
+     top: 100px;
+     left: 5px;
+     background-color: white;
+   }
+ </style>
+
   <div style="display: flex; flex-direction:column">
 
       <mat-tab-group [selectedIndex]="selected.value" (selectedIndexChange)="selected.setValue($event)"
 
       </mat-tab-group>
 
-
-
-
-
-        <div *ngFor="let tab of tabs; let index = index"
-          [style.display]='tab.active? "inline" : "none"'
-          [style.position]='tab.active? "static" : "absolute"'
-          [style.height]='tab.active? "calc(100vh)" : "calc(0vh)"'>
-
-          <iframe id="tabframe-{{tab.label.split(' ').join('-')}}-{{index}}" scrolling='yes' frameBorder='0' width='100%'
-            scrolling='yes' frameBorder='0' width='100%' height='90%' [src]='tab.url'></iframe>
-
-        </div>
-
-
-    </div>
+      <div class="apps-tab" *ngFor="let tab of tabs; let index = index"
+          [style.display]='"inline"'
+          [style.position]='"absolute"'
+          [style.height]='"calc(100vh)"'
+          [style.z-index]="tab.active? 1 : 0"
+          [style.opacity]="tab.active? 1 : 0"
+      >
+          <iframe id="tabframe-{{tab.label.split(' ').join('-')}}-{{index}}" scrolling='yes' frameBorder='0'
+            scrolling='yes' frameBorder='0' width='100%' height='90%' [src]='tab.url'>
+          </iframe>
+      </div>
+</div>
index d898563..54df2d1 100644 (file)
@@ -40,7 +40,7 @@
     <h1 class="heading-page">Edit Functional Menu</h1>
   </div>
   <div id="jqTree"></div>
-  <div class="functional-admin-button-container">
+  <!-- <div class="functional-admin-button-container">
     <button id="regenrate-functionalmenu-btn"
       class="btn btn-alt btn-small"
       (click)="regenerateFunctionalMenuAncestors()">Regenerate Menu
@@ -48,5 +48,5 @@
     <div class="regenerate-functionalmenu-btn-txt">
       <span class="n16r">Click when you are done with your changes.</span>
     </div>
-  </div>
+  </div> -->
 </div>
index d3b5a16..c231061 100644 (file)
@@ -151,43 +151,42 @@ export class FunctionalMenuComponent implements OnInit {
    * @param ngbModal 
    */
   buildTree(treedataarray,ngbModal: NgbModal , _self){
-    //console.log("treedataarray>>>>",treedataarray);
-  //   $(function() {
-  //       $('#jqTree').tree('loadData', treedataarray);
-  //       $('#jqTree').tree({
-  //           data: treedataarray,
-  //           autoOpen: false,
-  //           dragAndDrop: true,
-  //           onCreateLi: function(node, $li) {
-  //               ////console.log("node >>",node);
-  //           }
-  //       }).on(
-  //         'tree.contextmenu',
-  //         function(event:any) {
-  //             // The clicked node is 'event.node'
-  //             var node = event.node;
-  //             openMenuDetailsModal(node, "view");
-  //         }
-  //       );
+    console.log("treedataarray>>>>",treedataarray);
+    $(function() {
+        (<any>$('#jqTree')).tree('loadData', treedataarray);
+        (<any>$('#jqTree')).tree({
+            data: treedataarray,
+            autoOpen: false,
+            dragAndDrop: true,
+            onCreateLi: function(node, $li) {
+                ////console.log("node >>",node);
+            }
+        }).on(
+          'tree.contextmenu',
+          function(event:any) {
+              // The clicked node is 'event.node'
+              var node = event.node;
+              openMenuDetailsModal(node, "view");
+          }
+        );
 
-  //       var openMenuDetailsModal = function(node: any, actionName: string ){
-  //         const modalRef = ngbModal.open(FunctionalMenuDialogComponent, { size: 'lg' });
-  //         modalRef.componentInstance.title = 'Functional Menu ',actionName;
-  //         if(node != 'undefined' && node){
-  //           modalRef.componentInstance.nodedata = node;
-  //           modalRef.componentInstance.operationName = actionName;
-  //         }else{
-  //           modalRef.componentInstance.nodedata  = {};
-  //         }
-  //         modalRef.componentInstance.passEntry.subscribe((receivedEntry: any) => {
-  //           //console.log("receivedEntry>>>>",receivedEntry);
-  //           ngbModal.dismissAll();
-  //           if(receivedEntry.httpStatusCode===200){
-  //             _self.getFunctionalMenu();
-  //           }
-  //         });
-  //       }
-  //    });
-  // }
+        var openMenuDetailsModal = function(node: any, actionName: string ){
+          const modalRef = ngbModal.open(FunctionalMenuDialogComponent, { size: 'lg' });
+          modalRef.componentInstance.title = 'Functional Menu ',actionName;
+          if(node != 'undefined' && node){
+            modalRef.componentInstance.nodedata = node;
+            modalRef.componentInstance.operationName = actionName;
+          }else{
+            modalRef.componentInstance.nodedata  = {};
+          }
+          modalRef.componentInstance.passEntry.subscribe((receivedEntry: any) => {
+            //console.log("receivedEntry>>>>",receivedEntry);
+            ngbModal.dismissAll();
+            if(receivedEntry.httpStatusCode===200){
+              _self.getFunctionalMenu();
+            }
+          });
+        }
+     });
   }
 }
index c72d11e..7e68e1a 100644 (file)
     padding-bottom: 15px;
     padding-right: 40px;
     font-weight: bold;
+    white-space: nowrap;
+}
+
+td.mat-cell, td.mat-footer-cell, th.mat-header-cell {
+   padding-right: 45px;
 }
 
 .ion-md-trash{
index 6d0c544..f68d879 100644 (file)
                                                                <span style="flex: 9">Upload
                                                                        Image</span>
                                                                <app-information-tooltip style="flex: 1;"
-                                                                       [textMessage]="'Image file must be smaller than 1MB'">
+                                                                       [textMessage]="'Image file(.png or.jpg or.jpeg with dimension 200X200 pixel) must be smaller than 1MB.'">
                                                                </app-information-tooltip>
                                                        </div>
-                                                       <input type="file" id="input-app-image-upload"
+                                                       <input #inputAppImageUpload type="file" id="input-app-image-upload"
                                                                class="input-file-field input-app-image-upload-ht" accept="image/*"
                                                                [(ngModel)]="applicationObj.originalImage" name="appImage"
                                                                image-upload="applicationObj.originalImage" image-upload-resize-max-height="300"
                                                <div class="property" *ngIf="!(applicationObj.applicationType == '3')">
                                                        <div class="property-label preview">
                                                                <span class="left-label">Preview</span>
-                                                               <span class="remove" (click)="removeImage()">Remove</span>
+                                                               <span *ngIf="(applicationObj.imageLink && applicationObj.imageLink.indexOf('default_app_image.gif') == -1
+                                                               ||applicationObj.thumbnail && applicationObj.thumbnail.indexOf('default_app_image.gif') == -1
+                                                               ||emptyImgForPreview && emptyImgForPreview.indexOf('default_app_image.gif') == -1)" 
+                                                               class="remove" (click)="removeImage()">Remove</span>
                                                        </div>
                                                        <img id="image-app-preview" class="image-preview"
                                                                src="{{applicationObj.imageLink || applicationObj.thumbnail || emptyImgForPreview}}" />
index 1b15f80..852e970 100644 (file)
@@ -75,6 +75,7 @@ export class ApplicationDetailsDialogComponent implements OnInit {
   @Input() action: any;
   @Output() passEntry: EventEmitter<any> = new EventEmitter();
   @ViewChild('applicationName') applicationNameElement: ElementRef;
+  @ViewChild('inputAppImageUpload') inputAppImageUpload: ElementRef;
 
   newAppModel = {
     'id': null,
@@ -200,6 +201,7 @@ export class ApplicationDetailsDialogComponent implements OnInit {
         this.applicationObj.imageUrl = null;
         this.applicationObj.imageLink = null;
         this.emptyImgForPreview = '../../../assets/images/default_app_image.gif';
+        this.inputAppImageUpload.nativeElement.value = "";
       }
     }, (resut) => {
       return;
index 19f5d8a..4772247 100644 (file)
@@ -51,6 +51,7 @@
             </button>
           
             <div class="apps-table">
+                <span class="ecomp-spinner" *ngIf="showEcompSpinner"></span>
                 <!-- Applications Table goes here-->
                 <table mat-table [dataSource]="dataSource" matSort>
                     <!-- Thumbnail Column -->
index 5903d65..83cbfa0 100644 (file)
@@ -66,6 +66,7 @@ export class ApplicationOnboardingComponent implements OnInit {
   dataSource = new MatTableDataSource(this.appsList);
   @ViewChild(MatSort) sort: MatSort;
   @ViewChild(MatPaginator) paginator: MatPaginator;
+  showEcompSpinner:boolean = false;
 
   constructor(public applicationsService: ApplicationsService, public ngbModal: NgbModal) { }
 
@@ -77,11 +78,13 @@ export class ApplicationOnboardingComponent implements OnInit {
 
   getOnboardingApps(){
     //console.log("getOnboardingApps called");
+    this.showEcompSpinner = true;
     this.applicationsService.getOnboardingApps()
       .subscribe(_data => {
           this.result = _data;
           if (this.result == null || this.result == 'undefined') {
               console.log('WidgetOnboardingService::getOnboardingWidgets Failed: Result or result.data is null');
+              this.showEcompSpinner = false;
           }else {
             this.appsList = _data;
             for (var i = 0; i < this.appsList.length; i++) {
@@ -94,11 +97,14 @@ export class ApplicationOnboardingComponent implements OnInit {
               }                                        
             }
             this.populateTableData(this.appsList);
+            this.showEcompSpinner = false;
           }
       }, error =>{
         console.log(error);
+        this.showEcompSpinner = false;
         this.openConfirmationModal('Error', error.message);
     });
+    this.showEcompSpinner = false;
   }
 
   applyFilter(filterValue: string) {
@@ -143,13 +149,16 @@ export class ApplicationOnboardingComponent implements OnInit {
           console.log('ApplicationOnboardingCtrl::deleteApplication: No apllication or ID... cannot delete');
           return;
         }
+        this.showEcompSpinner = true;
         this.appsList.splice(this.appsList.indexOf(application), 1);
         this.applicationsService.deleteOnboardingApp(application.id)
           .subscribe( data => {
             this.result = data;
             this.getOnboardingApps();
+            this.showEcompSpinner = false;
           }, error => {
             console.log(error);
+            this.showEcompSpinner = false;
             if(error && error.status == 405){
               this.openConfirmationModal('', 'Application : ' + application.appName+ ' can not be deleted as it is associsted with one of the Microservices.');
             }else{