Fix VSP update for checked-in resources 93/120693/1
authorandre.schmid <andre.schmid@est.tech>
Thu, 15 Apr 2021 17:47:55 +0000 (18:47 +0100)
committerAndré Schmid <andre.schmid@est.tech>
Tue, 20 Apr 2021 10:30:55 +0000 (10:30 +0000)
Checkout the VF (if checked-in) related to the VSP before loading the VF
workspace.

Change-Id: I9576fd5b429fdae2ac00de5bfbd38e183b93be59
Issue-ID: SDC-3560
Signed-off-by: André Schmid <andre.schmid@est.tech>
catalog-ui/src/app/models/component-lifecycle-state.enum.ts [new file with mode: 0644]
catalog-ui/src/app/ng2/components/modals/onboarding-modal/import-vsp.service.ts
catalog-ui/src/app/ng2/components/modals/onboarding-modal/onboarding-modal.component.ts
catalog-ui/src/app/ng2/pages/home/__snapshots__/home.component.spec.ts.snap
catalog-ui/src/app/ng2/pages/home/home.component.spec.ts
catalog-ui/src/app/ng2/pages/home/home.component.ts
catalog-ui/src/app/ng2/pages/home/home.module.ts
catalog-ui/src/app/ng2/services/component-services/resource.service.spec.ts [new file with mode: 0644]
catalog-ui/src/app/ng2/services/component-services/resource.service.ts
catalog-ui/src/app/view-models/workspace/tabs/general/general-view-model.ts

diff --git a/catalog-ui/src/app/models/component-lifecycle-state.enum.ts b/catalog-ui/src/app/models/component-lifecycle-state.enum.ts
new file mode 100644 (file)
index 0000000..2861e43
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2021 Nordix Foundation
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://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
+ *  ============LICENSE_END=========================================================
+ */
+
+export enum ComponentLifecycleState {
+  CHECKOUT = 'checkout',
+  CHECKIN = 'checkin',
+  CERTIFICATION_REQUEST = 'certificationRequest',
+  UNDO_CHECKOUT = 'undoCheckout',
+  CANCEL_CERTIFICATION = 'cancelCertification',
+  START_CERTIFICATION = 'startCertification',
+  FAIL_CERTIFICATION = 'failCertification',
+  CERTIFY = 'certify',
+  DISTRIBUTE = 'distribute'
+}
index 8e73646..ad80bcd 100644 (file)
@@ -1,8 +1,7 @@
 import { Injectable, Inject } from "@angular/core";
-import { OnboardingModalComponent } from "./onboarding-modal.component";
+import {ImportVSPdata, OnboardingModalComponent} from "./onboarding-modal.component";
 import { SdcUiServices, SdcUiCommon } from "onap-ui-angular";
 import { Observable, Subject } from "rxjs";
-import { CHANGE_COMPONENT_CSAR_VERSION_FLAG } from "../../../../utils/constants";
 import { CacheService } from "../../../services/cache.service";
 
 
@@ -25,7 +24,7 @@ export class ImportVSPService {
         } as SdcUiCommon.IModalConfig;
         const onboardingModalInstance = this.modalService.openCustomModal(onboardingModalConfig, OnboardingModalComponent, {currentCsarUUID: csarUUID, currentCsarVersion: csarVersion});
         onboardingModalInstance.innerModalContent.instance.closeModalEvent.subscribe(
-            (result: any) => {
+            (result: ImportVSPdata) => {
                 subject.next(result);
                 onboardingModalInstance.closeModal(); 
             }, (err) =>{}
index 10d7f67..1e07c8b 100644 (file)
@@ -18,6 +18,12 @@ export interface ImportVSPdata {
     componentCsar: Resource;
     previousComponent?: Resource;
     type: string;
+    actionType: ImportVSPActionType;
+}
+
+export enum ImportVSPActionType {
+    IMPORT_VSP,
+    UPDATE_VSP
 }
 
 // tslint:disable-next-line:interface-name
@@ -118,13 +124,14 @@ export class OnboardingModalComponent implements OnInit {
     }
 
     importOrUpdateCsar = (): void => {
-        const selectedComponentConverted = this.onBoardingService.convertMetaDataToComponent(this.selectedComponent);
+        const selectedComponentConverted: Resource = this.onBoardingService.convertMetaDataToComponent(this.selectedComponent);
         const componentFromServerConverted = this.componentFromServer ?
             this.onBoardingService.convertMetaDataToComponent(this.componentFromServer) : undefined;
         const importVSPdata: ImportVSPdata = {
             componentCsar: selectedComponentConverted,
             previousComponent: componentFromServerConverted,
-            type: ComponentType.RESOURCE.toLowerCase()
+            type: ComponentType.RESOURCE.toLowerCase(),
+            actionType: this.isCsarComponentExists ? ImportVSPActionType.UPDATE_VSP : ImportVSPActionType.IMPORT_VSP
         };
         this.closeModalEvent.emit(importVSPdata);
     }
index ae5445e..42686c1 100644 (file)
@@ -13,6 +13,7 @@ exports[`home component should match current snapshot 1`] = `
   loaderService={[Function Object]}
   modalService={[Function Object]}
   modalsHandler={[Function Object]}
+  resourceService={[Function Object]}
   sdcConfig={[Function Object]}
   sdcMenu={[Function Object]}
   translateService={[Function Object]}
index df85402..1c03790 100644 (file)
@@ -1,22 +1,17 @@
+import {SdcConfigToken} from "../../config/sdc-config.config";
+import {SdcMenuToken} from "../../config/sdc-menu.config";
 
-import { SdcConfigToken, ISdcConfig } from "../../config/sdc-config.config";
-import { SdcMenuToken, IAppMenu } from "../../config/sdc-menu.config";
 
-
-import { async, ComponentFixture, TestBed } from "@angular/core/testing";
-import { HomeComponent } from "./home.component";
+import {async, ComponentFixture, TestBed} from "@angular/core/testing";
+import {HomeComponent} from "./home.component";
 import {ConfigureFn, configureTests} from "../../../../jest/test-config.helper";
 import {NO_ERRORS_SCHEMA} from "@angular/core";
-import { TranslateService } from "../../shared/translator/translate.service";
-import { HomeService, CacheService, AuthenticationService, ImportVSPService } from '../../../../app/services-ng2';
-import { ModalsHandler } from "../../../../app/utils";
-import { SdcUiServices } from "onap-ui-angular";
+import {TranslateService} from "../../shared/translator/translate.service";
+import {AuthenticationService, CacheService, HomeService, ImportVSPService, ResourceServiceNg2} from '../../../../app/services-ng2';
+import {ModalsHandler} from "../../../../app/utils";
+import {SdcUiServices} from "onap-ui-angular";
 import {ComponentType, ResourceType} from "../../../utils/constants";
-import { FoldersMenu, FoldersItemsMenu, FoldersItemsMenuGroup } from './folders';
-import { HomeFilter } from "../../../../app/models/home-filter";
-import {Component} from "../../../models/components/component";
-
-
+import {HomeFilter} from "../../../models/home-filter";
 
 
 describe('home component', () => {
@@ -33,6 +28,7 @@ describe('home component', () => {
     let homeFilterMock :Partial<HomeFilter>;
     let foldersMock;
     let loaderServiceMock;
+    let resourceServiceNg2Mock: Partial<ResourceServiceNg2>;
 
 
     beforeEach(
@@ -62,7 +58,11 @@ describe('home component', () => {
             loaderServiceMock = {
                 activate: jest.fn(),
                 deactivate: jest.fn()
-            }
+            };
+
+            resourceServiceNg2Mock = {
+                checkout: jest.fn()
+            };
 
             const configure: ConfigureFn = testBed => {
                 testBed.configureTestingModule({
@@ -80,7 +80,8 @@ describe('home component', () => {
                         {provide: ModalsHandler, useValue: {}},
                         {provide: SdcUiServices.ModalService, useValue: modalServiceMock},
                         {provide: SdcUiServices.LoaderService, useValue: loaderServiceMock},
-                        {provide: ImportVSPService, useValue: {}}
+                        {provide: ImportVSPService, useValue: {}},
+                        {provide: ResourceServiceNg2, useValue: resourceServiceNg2Mock}
                     ],
                 });
             };
index 77fd3b5..f0e8815 100644 (file)
  * ============LICENSE_END=========================================================
  */
 'use strict';
-import { Component as NgComponent, Inject, OnInit } from '@angular/core';
-import { Component, IConfigRoles, IUserProperties, Resource } from 'app/models';
-import { HomeFilter } from 'app/models/home-filter';
-import { AuthenticationService, CacheService, HomeService } from 'app/services-ng2';
-import { ModalsHandler } from 'app/utils';
-import { SdcUiServices } from 'onap-ui-angular';
-import { CHANGE_COMPONENT_CSAR_VERSION_FLAG, ComponentType, ResourceType } from '../../../utils/constants';
-import { ImportVSPService } from '../../components/modals/onboarding-modal/import-vsp.service';
-import { ISdcConfig, SdcConfigToken } from '../../config/sdc-config.config';
-import { IAppMenu, SdcMenuToken } from '../../config/sdc-menu.config';
-import { EntityFilterPipe } from '../../pipes/entity-filter.pipe';
-import { TranslateService } from '../../shared/translator/translate.service';
-import { FoldersItemsMenu, FoldersItemsMenuGroup, FoldersMenu } from './folders';
+import {Component as NgComponent, Inject, OnInit} from '@angular/core';
+import {Component, ComponentMetadata, IConfigRoles, IUserProperties, Resource} from 'app/models';
+import {HomeFilter} from 'app/models/home-filter';
+import {AuthenticationService, CacheService, HomeService, ResourceServiceNg2} from 'app/services-ng2';
+import {ComponentState, ModalsHandler} from 'app/utils';
+import {SdcUiServices} from 'onap-ui-angular';
+import {CHANGE_COMPONENT_CSAR_VERSION_FLAG, ComponentType, ResourceType} from '../../../utils/constants';
+import {ImportVSPService} from '../../components/modals/onboarding-modal/import-vsp.service';
+import {ISdcConfig, SdcConfigToken} from '../../config/sdc-config.config';
+import {IAppMenu, SdcMenuToken} from '../../config/sdc-menu.config';
+import {EntityFilterPipe} from '../../pipes/entity-filter.pipe';
+import {TranslateService} from '../../shared/translator/translate.service';
+import {FoldersItemsMenu, FoldersItemsMenuGroup, FoldersMenu} from './folders';
+import {ImportVSPdata} from "../../components/modals/onboarding-modal/onboarding-modal.component";
 
 @NgComponent({
     selector: 'home-page',
@@ -63,8 +64,9 @@ export class HomeComponent implements OnInit {
         private modalsHandler: ModalsHandler,
         private modalService: SdcUiServices.ModalService,
         private loaderService: SdcUiServices.LoaderService,
-        private importVSPService: ImportVSPService
-    ) {}
+        private importVSPService: ImportVSPService,
+        private resourceService: ResourceServiceNg2
+    ) { }
 
     ngOnInit(): void {
         this.initHomeComponentVars();
@@ -90,16 +92,38 @@ export class HomeComponent implements OnInit {
 
     // Open onboarding modal
     public notificationIconCallback(): void {
-        this.importVSPService.openOnboardingModal().subscribe((result) => {
-            if (!result.previousComponent || result.previousComponent.csarVersion !== result.componentCsar.csarVersion) {
-                this.cacheService.set(CHANGE_COMPONENT_CSAR_VERSION_FLAG, result.componentCsar.csarVersion);
+        this.importVSPService.openOnboardingModal().subscribe((importVSPdata: ImportVSPdata) => {
+            const actualComponent = importVSPdata.previousComponent;
+            if (!actualComponent || actualComponent.csarVersion !== importVSPdata.componentCsar.csarVersion) {
+                this.cacheService.set(CHANGE_COMPONENT_CSAR_VERSION_FLAG, importVSPdata.componentCsar.csarVersion);
             }
+            const vfExistsAndIsNotCheckedOut: boolean = actualComponent && actualComponent.lifecycleState != ComponentState.NOT_CERTIFIED_CHECKOUT;
+            if (vfExistsAndIsNotCheckedOut) {
+                this.checkoutAndRedirectToWorkspace(importVSPdata);
+                return;
+            }
+            this.$state.go('workspace.general', {
+                id: actualComponent && actualComponent.uniqueId,
+                componentCsar: importVSPdata.componentCsar,
+                type: importVSPdata.type
+            });
+        });
+    }
+
+    private checkoutAndRedirectToWorkspace(importVSPdata: ImportVSPdata) {
+        this.loaderService.activate();
+        this.resourceService.checkout(importVSPdata.previousComponent.uniqueId)
+        .subscribe((componentMetadata: ComponentMetadata) => {
             this.$state.go('workspace.general', {
-                id: result.previousComponent && result.previousComponent.uniqueId,
-                componentCsar: result.componentCsar,
-                type: result.type
+                id: componentMetadata.uniqueId,
+                componentCsar: importVSPdata.componentCsar,
+                type: importVSPdata.type
             });
+            this.loaderService.deactivate();
+        }, () => {
+            this.loaderService.deactivate();
         });
+        return;
     }
 
     public onImportVf(file: any): void {
index 3e7c0cd..1a397b4 100644 (file)
@@ -6,6 +6,7 @@ import { UiElementsModule } from "../../components/ui/ui-elements.module";
 import { GlobalPipesModule } from "../../pipes/global-pipes.module";
 import { TranslateModule } from "../../shared/translator/translate.module";
 import { SdcUiComponentsModule } from "onap-ui-angular";
+import { ResourceServiceNg2 } from "../../services/component-services/resource.service";
 
 @NgModule({
     declarations: [
@@ -25,7 +26,7 @@ import { SdcUiComponentsModule } from "onap-ui-angular";
     entryComponents: [
         HomeComponent
     ],
-    providers: []
+    providers: [ResourceServiceNg2]
 })
 export class HomeModule {
 }
diff --git a/catalog-ui/src/app/ng2/services/component-services/resource.service.spec.ts b/catalog-ui/src/app/ng2/services/component-services/resource.service.spec.ts
new file mode 100644 (file)
index 0000000..062797b
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2021 Nordix Foundation
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://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
+ *  ============LICENSE_END=========================================================
+ */
+
+import {inject, TestBed} from '@angular/core/testing';
+
+import {ResourceServiceNg2} from "./resource.service";
+import {HttpClient} from "@angular/common/http";
+import {ISdcConfig, SdcConfigToken} from "../../config/sdc-config.config";
+
+describe('ResourceServiceNg2', () => {
+  beforeEach(() => {
+    const sdcConfigToken: Partial<ISdcConfig> = {
+      'api': {
+        'root': 'testRoot',
+        'component_api_root': 'testApiRoot',
+      }
+    };
+    let httpServiceMock: Partial<HttpClient> = {
+      get: jest.fn()
+    };
+    TestBed.configureTestingModule({
+      providers: [ResourceServiceNg2,
+        {provide: SdcConfigToken, useValue: sdcConfigToken},
+        {provide: HttpClient, useValue: httpServiceMock}
+      ]
+    });
+  });
+
+  it('should be created', inject([ResourceServiceNg2], (service: ResourceServiceNg2) => {
+    expect(service).toBeTruthy();
+  }));
+});
index d20f541..2f84418 100644 (file)
  * ============LICENSE_END=========================================================
  */
 
-import { Injectable } from '@angular/core';
-import 'rxjs/add/operator/map';
-import 'rxjs/add/operator/toPromise';
-import { HttpClient } from '@angular/common/http';
+import {Inject, Injectable} from '@angular/core';
+import {HttpClient} from '@angular/common/http';
+import {ISdcConfig, SdcConfigToken} from "../../config/sdc-config.config";
+import {Observable} from "rxjs/Observable";
+import {ComponentMetadata} from "../../../models/component-metadata";
+import {ComponentLifecycleState} from "../../../models/component-lifecycle-state.enum";
 
 @Injectable()
 export class ResourceServiceNg2 {
 
-    protected baseUrl = "";
-
-    constructor(private http: HttpClient) {
-
-    }
+  private readonly baseUrl: string;
 
+  constructor(protected http: HttpClient, @Inject(SdcConfigToken) sdcConfig: ISdcConfig) {
+    this.baseUrl = sdcConfig.api.root + sdcConfig.api.component_api_root;
+  }
 
+  public checkout(componentUniqueId: string): Observable<ComponentMetadata> {
+    return this.changeLifecycleState(componentUniqueId, ComponentLifecycleState.CHECKOUT);
+  }
 
+  private changeLifecycleState(componentUniqueId: string, state: ComponentLifecycleState): Observable<ComponentMetadata> {
+    const url: string = this.baseUrl + 'resources/' + componentUniqueId + '/lifecycleState/' + state;
+    return this.http.post<ComponentMetadata>(url, {}).map(value => {
+          return value;
+        }
+    );
+  }
 
 }
index 2876544..b456bec 100644 (file)
 
 'use strict';
 import * as _ from "lodash";
-import {ModalsHandler, ValidationUtils, EVENTS, CHANGE_COMPONENT_CSAR_VERSION_FLAG, ComponentType, DEFAULT_ICON,
-    ResourceType, ComponentState, instantiationType, ComponentFactory} from "app/utils";
-import { EventListenerService, ProgressService} from "app/services";
-import {CacheService, OnboardingService, ImportVSPService, ElementService} from "app/services-ng2";
-import {IAppConfigurtaion, IValidate, IMainCategory, Resource, ISubCategory,Service, ICsarComponent, Component, IMetadataKey} from "app/models";
-import {IWorkspaceViewModelScope} from "app/view-models/workspace/workspace-view-model";
 import {Dictionary} from "lodash";
-import { PREVIOUS_CSAR_COMPONENT, CATEGORY_SERVICE_METADATA_KEYS } from "../../../../utils/constants";
-import { Observable, Subject } from "rxjs";
-import { MetadataEntry } from "app/models/metadataEntry";
-import { Metadata } from "app/models/metadata";
+import {
+    ComponentFactory,
+    ComponentState,
+    ComponentType,
+    DEFAULT_ICON,
+    EVENTS,
+    instantiationType,
+    ModalsHandler,
+    ResourceType,
+    ValidationUtils
+} from "app/utils";
+import {EventListenerService, ProgressService} from "app/services";
+import {CacheService, ElementService, ImportVSPService, OnboardingService} from "app/services-ng2";
+import {Component, IAppConfigurtaion, ICsarComponent, IMainCategory, IMetadataKey, ISubCategory, IValidate, Resource, Service} from "app/models";
+import {IWorkspaceViewModelScope} from "app/view-models/workspace/workspace-view-model";
+import {CATEGORY_SERVICE_METADATA_KEYS, PREVIOUS_CSAR_COMPONENT} from "../../../../utils/constants";
+import {Observable} from "rxjs";
 
 export class Validation {
     componentNameValidationPattern:RegExp;
@@ -272,19 +279,9 @@ export class GeneralViewModel {
 
         if (this.$stateParams.componentCsar && !this.$scope.isCreateMode()) {
             this.$scope.updateUnsavedFileFlag(true);
-            // We are coming from update VSP modal we need to automatically checkout (if needed) and save the VF
-            if (this.$scope.component.lifecycleState !== ComponentState.NOT_CERTIFIED_CHECKOUT) {
-                // Checkout is needed after that a save will be invoked in workspace-view.handleLifeCycleStateChange
-                this.EventListenerService.notifyObservers(EVENTS.ON_LIFECYCLE_CHANGE_WITH_SAVE, 'checkOut');
-                // if(this.$scope.component.lifecycleState !== 'NOT_CERTIFIED_CHECKIN') {
-                //     (<Resource>this.$scope.component).csarVersion = this.$stateParams.componentCsar.csarVersion;
-                // }
-            } else {
-                this.$scope.save();
-            }
+            this.$scope.save();
         }
 
-
         if (this.$scope.component.isResource() &&
             (this.$scope.component as Resource).resourceType === ResourceType.VF ||
                 (this.$scope.component as Resource).resourceType === ResourceType.PNF && (this.$scope.component as Resource).csarUUID) {