aboutsummaryrefslogtreecommitdiffstats
path: root/catalog-ui/src/app/ng2/pages/workspace/deployment/panel
diff options
context:
space:
mode:
Diffstat (limited to 'catalog-ui/src/app/ng2/pages/workspace/deployment/panel')
-rw-r--r--catalog-ui/src/app/ng2/pages/workspace/deployment/panel/panel-tabs/edit-module-name/edit-module-name.component.html29
-rw-r--r--catalog-ui/src/app/ng2/pages/workspace/deployment/panel/panel-tabs/edit-module-name/edit-module-name.component.less20
-rw-r--r--catalog-ui/src/app/ng2/pages/workspace/deployment/panel/panel-tabs/edit-module-name/edit-module-name.component.ts24
-rw-r--r--catalog-ui/src/app/ng2/pages/workspace/deployment/panel/panel-tabs/hierarchy-tab/hierarchy-tab.component.html119
-rw-r--r--catalog-ui/src/app/ng2/pages/workspace/deployment/panel/panel-tabs/hierarchy-tab/hierarchy-tab.component.less222
-rw-r--r--catalog-ui/src/app/ng2/pages/workspace/deployment/panel/panel-tabs/hierarchy-tab/hierarchy-tab.component.spec.ts133
-rw-r--r--catalog-ui/src/app/ng2/pages/workspace/deployment/panel/panel-tabs/hierarchy-tab/hierarchy-tab.component.ts139
-rw-r--r--catalog-ui/src/app/ng2/pages/workspace/deployment/panel/panel-tabs/hierarchy-tab/hierarchy-tab.module.ts24
8 files changed, 710 insertions, 0 deletions
diff --git a/catalog-ui/src/app/ng2/pages/workspace/deployment/panel/panel-tabs/edit-module-name/edit-module-name.component.html b/catalog-ui/src/app/ng2/pages/workspace/deployment/panel/panel-tabs/edit-module-name/edit-module-name.component.html
new file mode 100644
index 0000000000..d5b9d9e9b2
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/workspace/deployment/panel/panel-tabs/edit-module-name/edit-module-name.component.html
@@ -0,0 +1,29 @@
+<div class="edit-module-name">
+ <div class="edit-module-name-label vfInstance-name" data-tests-id="popover-vfinstance-name" sdc-tooltip [tooltip-text]="selectModule.vfInstanceName">{{selectModule.vfInstanceName}}</div>
+ <div class="edit-module-name-heatName">
+ <sdc-input #heatName [maxLength]="50"
+ [(value)]="selectModule.heatName"
+ [testId]="'popover-heat-name'"
+ [placeHolder]="'Enter Name'">
+ </sdc-input>
+ <sdc-validation [validateElement]="heatName">
+ <sdc-regex-validator [message]="'Special characters not allowed.'" [pattern]="pattern"></sdc-regex-validator>
+ </sdc-validation>
+ </div>
+ <div class="edit-module-name-label module-name" data-tests-id="'popover-module-name'" sdc-tooltip [tooltip-text]="selectModule.moduleName">{{selectModule.moduleName}}</div>
+ <sdc-button class="edit-module-name-btn cancel-button"
+ [text]="'Cancel'"
+ [testId]="'popover-close-button'"
+ [type]="'primary'"
+ [size] = "'small'"
+ (click)="clickButton(false)">
+ </sdc-button>
+ <sdc-button class="edit-module-name-btn save-button"
+ [text]="'Save'"
+ [testId]="'popover-save-button'"
+ [type]="'primary'"
+ [size] = "'small'"
+ (click)="clickButton(true)"
+ [disabled]="selectModule.heatName == originalName">
+ </sdc-button>
+</div> \ No newline at end of file
diff --git a/catalog-ui/src/app/ng2/pages/workspace/deployment/panel/panel-tabs/edit-module-name/edit-module-name.component.less b/catalog-ui/src/app/ng2/pages/workspace/deployment/panel/panel-tabs/edit-module-name/edit-module-name.component.less
new file mode 100644
index 0000000000..721ad53bc3
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/workspace/deployment/panel/panel-tabs/edit-module-name/edit-module-name.component.less
@@ -0,0 +1,20 @@
+.edit-module-name-btn{
+ float:right;
+ margin-left: 10px;
+ margin-bottom: 20px;
+}
+.save-button {
+ margin-left: 30px;
+}
+.cancel-button {
+ margin-left: 20px;
+}
+.edit-module-name-heatName {
+ margin-bottom: 15px;
+}
+.edit-module-name-label {
+ text-overflow: ellipsis;
+ display: block;
+ white-space: nowrap;
+ margin-bottom: 10px;
+}
diff --git a/catalog-ui/src/app/ng2/pages/workspace/deployment/panel/panel-tabs/edit-module-name/edit-module-name.component.ts b/catalog-ui/src/app/ng2/pages/workspace/deployment/panel/panel-tabs/edit-module-name/edit-module-name.component.ts
new file mode 100644
index 0000000000..819182c75f
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/workspace/deployment/panel/panel-tabs/edit-module-name/edit-module-name.component.ts
@@ -0,0 +1,24 @@
+import { Component, Input, Output, OnInit } from "@angular/core";
+import { EventEmitter } from "@angular/core";
+import { DisplayModule } from "../../../../../../../models/modules/base-module";
+import { ValidationConfiguration } from "../../../../../../../models/validation-config";
+
+@Component({
+ selector: 'edit-module-name',
+ templateUrl: './edit-module-name.component.html',
+ styleUrls: ['edit-module-name.component.less']
+})
+export class EditModuleName implements OnInit{
+ @Input() selectModule:DisplayModule;
+ @Output() clickButtonEvent: EventEmitter<String> = new EventEmitter();
+ private pattern = ValidationConfiguration.validation.validationPatterns.stringOrEmpty;
+ private originalName: string;
+ constructor(){}
+ public ngOnInit(): void {
+ this.originalName = this.selectModule.heatName;
+ }
+
+ private clickButton(saveOrCancel: boolean) : void {
+ this.clickButtonEvent.emit(saveOrCancel ? this.selectModule.heatName : null);
+ }
+} \ No newline at end of file
diff --git a/catalog-ui/src/app/ng2/pages/workspace/deployment/panel/panel-tabs/hierarchy-tab/hierarchy-tab.component.html b/catalog-ui/src/app/ng2/pages/workspace/deployment/panel/panel-tabs/hierarchy-tab/hierarchy-tab.component.html
new file mode 100644
index 0000000000..7c0e60b814
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/workspace/deployment/panel/panel-tabs/hierarchy-tab/hierarchy-tab.component.html
@@ -0,0 +1,119 @@
+<div class="sdc-hierarchy-tab" ng-class="">
+ <sdc-loader [global]="false" [testId]="'hierarchy-tab-loader'" [active]="isLoading" [relative]="true" [size]="'medium'"></sdc-loader>
+ <div class="sdc-hierarchy-tab-title"
+ [attr.data-tests-id]="'tab-header'">{{'DEPLOYMENT_TAB_TITLE' | translate }}</div>
+ <div [ngClass]="{'scroll-module-list': selectedModule}">
+ <div *ngIf="topologyTemplateType != 'SERVICE'; else isService" class="modules-list">
+ <div>
+ <div class="sdc-hierarchy-tab-sub-title" data-tests-id="tab-sub-header">{{topologyTemplateName}}</div>
+ <div *ngFor="let module of modules; index as i">
+ <sdc-accordion [title]="module.name" [arrow-direction]="'left'"
+ [css-class]="'expand-collapse-container'"
+ [ngClass]="{'selected': selectedModule !== undefined && selectedModule.uniqueId === module.uniqueId}"
+ [testId]="'hierarchy-module-' + i + '-title'" tooltip="{{module.name}}"
+ (click)="onModuleSelected(module)">
+ <div *ngFor="let memberId of getKeys(module.members)">
+ <div class="expand-collapse-sub-title" tooltip="{{memberId}}">{{memberId}}</div>
+ </div>
+ </sdc-accordion>
+ </div>
+ </div>
+ </div>
+
+ <ng-template #isService>
+ <div class="module-list">
+ <div *ngFor="let instance of componentInstances; index as instanceIndex">
+ <sdc-accordion [title]="instance.name" [arrow-direction]="'left'"
+ [css-class]="'expand-collapse-container outer-container'"
+ [testId]="'hierarchy-instance-' + instanceIndex + '-title'"
+ tooltip="{{instance.name}}">
+ <div *ngFor="let module of instance.groupInstances; index as moduleIndex">
+ <sdc-accordion [title]="module.name" [arrow-direction]="'left'"
+ [css-class]="'expand-collapse-container inner-container'"
+ [ngClass]="{'selected': selectedModule && selectedModule.groupInstanceUniqueId === module.uniqueId}"
+ [testId]="'hierarchy-module-' + moduleIndex + '-title'"
+ tooltip="{{module.uniqueId}}"
+ (click)="onModuleSelected(module, instance.uniqueId)">
+ <div *ngFor="let memberId of getKeys(module.members)">
+ <div class="expand-collapse-sub-title" tooltip="{{memberId}}">{{memberId}}</div>
+ </div>
+ </sdc-accordion>
+ </div>
+ </sdc-accordion>
+ </div>
+ </div>
+ </ng-template>
+
+ <!--TODO: Add Resizable-->
+ <div *ngIf="selectedModule"class="module-data-container" [attr.data-tests-id]="'selected-module-data'">
+ <div class="module-data">
+ <div class="module-name-container">
+ <div class="module-name module-text-overflow" [attr.data-tests-id]="'selected-module-name'"
+ tooltip="{{selectedModule.name}}">{{selectedModule.name}}</div>
+ <div class="edit-name-container" *ngIf="topologyTemplateType != 'SERVICE'">
+ <svg-icon name="edit-o" [size]="'medium'" [ngClass]="{'hand-pointer': !isViewOnly}" (click)="openEditModuleNamePopup($event)"></svg-icon>
+ </div>
+ </div>
+ <div [attr.data-tests-id]="'selected-module-group-uuid'" tooltip="{{selectedModule.groupUUID}}">
+ <div class="selected-module-property-header">Module ID:</div>
+ <div class="selected-module-property-value small-font">{{selectedModule.groupUUID}}</div>
+ </div>
+ <div [attr.data-tests-id]="'selected-module-group-customization-uuid'"
+ *ngIf="topologyTemplateType == 'SERVICE' && isViewOnly"
+ tooltip="{{selectedModule.customizationUUID}}">
+ <div class="selected-module-property-header">Customization ID:</div>
+ <div class="selected-module-property-value small-font">{{selectedModule.customizationUUID}}</div>
+ </div>
+ <div [attr.data-tests-id]="'selected-module-group-invariant-uuid'"
+ tooltip="{{selectedModule.invariantUUID}}">
+ <div class="selected-module-property-header">Invariant UUID:</div>
+ <div class="selected-module-property-value small-font">{{selectedModule.invariantUUID}}</div>
+ </div>
+ <div [attr.data-tests-id]="'selected-module-version'" class="selected-module-property-container">
+ <div class="selected-module-property-header">Version:</div>
+ <div class="selected-module-property-value same-row">{{selectedModule.version}}</div>
+ </div>
+ <div data-tests-id="selected-module-is-base" class="selected-module-property-container">
+ <div class="selected-module-property-header">IsBase:</div>
+ <div class="selected-module-property-value same-row">{{selectedModule.isBase}}</div>
+ </div>
+
+ </div>
+ <sdc-accordion [title]="'Properties'" [arrow-direction]="'right'"
+ [css-class]="'expand-collapse-module-data-container'">
+ <div *ngFor="let property of selectedModule.properties | orderBy:['name']:['asc']">
+ <div class="module-data-list-item">
+ <div class="module-data-list-item-value property-name"
+ [attr.data-tests-id]="'selected-module-property-name'">
+ <span tooltip="{{property.name}}" [ngClass]="{'hand-pointer': !isViewOnly}"
+ (click)="!isViewOnly && openEditPropertyModal(property)">{{property.name}}</span>
+ </div>
+ <div class="module-data-list-item-value property-info"
+ [attr.data-tests-id]="'selected-module-property-type'"> Type: {{property.type}}</div>
+ <div class="module-data-list-item-value property-info"
+ [attr.data-tests-id]="'selected-module-property-schema-type'">
+ Value: {{property.value}}</div>
+ </div>
+ </div>
+ </sdc-accordion>
+ <sdc-accordion [title]="'Artifacts'" [arrow-direction]="'right'"
+ [css-class]="'expand-collapse-module-data-container'">
+ <div *ngFor="let artifact of selectedModule.artifacts | orderBy:['artifactName']:['asc']">
+ <div class="module-data-list-item">
+ <div class="artifact-list-item">
+ <div class="module-data-list-item-value"
+ [attr.data-tests-id]="'selected-module-artifact-name'"
+ tooltip="{{artifact.artifactName}}">{{artifact.artifactName}}</div>
+ <div class="module-data-list-item-value artifact-info"
+ [attr.data-tests-id]="'selected-module-artifact-uuid'"
+ tooltip="{{artifact.artifactUUID}}">UUID: {{artifact.artifactUUID}}</div>
+ <div class="module-data-list-item-value artifact-info"
+ [attr.data-tests-id]="'selected-module-artifact-version'">
+ Version: {{artifact.artifactVersion}}</div>
+ </div>
+ </div>
+ </div>
+ </sdc-accordion>
+ </div>
+ </div>
+</div>
diff --git a/catalog-ui/src/app/ng2/pages/workspace/deployment/panel/panel-tabs/hierarchy-tab/hierarchy-tab.component.less b/catalog-ui/src/app/ng2/pages/workspace/deployment/panel/panel-tabs/hierarchy-tab/hierarchy-tab.component.less
new file mode 100644
index 0000000000..269ca0aee0
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/workspace/deployment/panel/panel-tabs/hierarchy-tab/hierarchy-tab.component.less
@@ -0,0 +1,222 @@
+@import './../../../../../../../../assets/styles/variables.less';
+.sdc-hierarchy-tab {
+ padding: 15px 0 0 0;
+ background-color: #f8f8f8;
+ height: 100%;
+ box-shadow: 0.3px 1px 3px rgba(24, 24, 25, 0.42);
+ display: flex;
+ flex-flow: column;
+
+ .sdc-hierarchy-tab-title {
+ color: @main_color_a;
+ padding: 0 0 15px 20px;
+ border-bottom: 1px solid #d2d2d2;
+ }
+
+ .sdc-hierarchy-tab-sub-title {
+ color: @main_color_a;
+ padding: 15px 20px 15px 20px;
+ }
+
+ .scroll-module-list {
+ overflow-y: auto;
+ display: flex;
+ height: 100%;
+ flex-direction: column;
+ }
+
+ /deep/ .expand-collapse-container {
+ margin-bottom: 0;
+
+ .sdc-accordion-header {
+ white-space: nowrap;
+ line-height: 22px;
+ background-color: @tlv_color_u;
+ padding: 8px 20px 8px 8px;
+ box-shadow: inset 0px -1px 0px 0px rgba(255, 255, 255, 0.7);
+ height: 40px;
+
+ .title {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ max-width: 215px;
+ }
+ }
+
+ .sdc-accordion-body.open {
+ padding: 0 0 5px 0;
+ }
+
+ .sdc-accordion-header:hover {
+ background-color: @main_color_o;
+ }
+
+ &.outer-container {
+ .sdc-accordion-body {
+ padding-left: 0;
+ }
+ }
+
+ &.inner-container {
+ margin-bottom: 0;
+
+ .sdc-accordion-header {
+ padding: 8px 20px 8px 30px;
+ background-color: @tlv_color_t
+ }
+ }
+ }
+
+ sdc-accordion.selected {
+ /deep/ .expand-collapse-container {
+ .sdc-accordion-header {
+ background-color: @main_color_a;
+ color: @main_color_p;
+
+ .svg-icon {
+ fill: @main_color_p;
+ }
+ }
+ }
+ }
+
+ .expand-collapse-sub-title {
+ max-width: 225px;
+ display: inline-block;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ padding: 10px 0 0 33px;
+ }
+
+ .expand-collapse-content {
+ .expand-collapse-title {
+ padding: 0 10px 0 30px;
+ }
+ }
+
+ .module-data-container {
+ width: 100%;
+ overflow-y: overlay;
+ background-color: @tlv_color_v;
+ border: 1px solid @main_color_a;
+ border-top: 4px solid @main_color_a;
+ box-shadow: 0.3px 1px 2px rgba(24, 24, 25, 0.32);
+ .module-data {
+ color: @main_color_a;
+ padding: 10px 0 10px 0;
+ margin: 0 20px 0 20px;
+
+ .selected-module-property-header {
+ font-weight: bold;
+ }
+
+ .selected-module-property-value {
+ font-family: @font-opensans-regular;
+
+ &.small-font {
+ font-size: 12px;
+ }
+ }
+
+ .module-name-container {
+
+ display: flex;
+ flex-direction: row;
+
+ .module-name {
+ font-size: 14px;
+ width: 75%;
+ max-width: 240px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+
+ .edit-name-container {
+ float: right;
+ border-left: 1px solid @main_color_a;
+ height: 20px;
+ padding-left: 12px;
+
+ svg-icon {
+ padding-top: 3px;
+ fill: @main_color_s;
+
+ &.hand-pointer {
+ cursor: pointer;
+ }
+
+ }
+ }
+ }
+ }
+
+ .selected-module-property-container {
+ flex-direction: row;
+ display: flex;
+
+ .selected-module-property-value {
+ text-indent: 2px;
+ }
+ }
+
+ /deep/ .expand-collapse-module-data-container {
+ margin-bottom: 0;
+
+ .sdc-accordion-header {
+ white-space: nowrap;
+ line-height: 22px;
+ padding: 8px 20px 8px 16px;
+ height: 40px;
+ background-color: @tlv_color_w;
+ color: @main_color_l;
+ border-top: 1px solid @main_color_a;
+ border-bottom: 1px solid @main_color_a;
+ width: 100%;
+ }
+
+ }
+
+ .module-data-list-item {
+ padding-bottom: 10px;
+ margin: 0 20px 0 20px;
+
+ .artifact-list-item {
+ color: @main_color_m;
+ }
+
+ .module-data-list-item-value {
+ width: 100%;
+ max-width: 240px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+
+ &.artifact-info {
+ font-family: @font-opensans-regular;
+ font-size: 12px;
+ }
+
+ &.property-name {
+ font-weight: 400;
+ color: @main_color_a;
+
+ .hand-pointer {
+ cursor: pointer;
+ }
+ }
+
+ &.property-info {
+ color: @func_color_s;
+ font-family: @font-opensans-regular;
+ }
+ }
+ }
+ }
+}
+
+.modules-list {
+ overflow-y: overlay;
+ flex-grow: 1;
+} \ No newline at end of file
diff --git a/catalog-ui/src/app/ng2/pages/workspace/deployment/panel/panel-tabs/hierarchy-tab/hierarchy-tab.component.spec.ts b/catalog-ui/src/app/ng2/pages/workspace/deployment/panel/panel-tabs/hierarchy-tab/hierarchy-tab.component.spec.ts
new file mode 100644
index 0000000000..ab88867cc0
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/workspace/deployment/panel/panel-tabs/hierarchy-tab/hierarchy-tab.component.spec.ts
@@ -0,0 +1,133 @@
+import {async, ComponentFixture} from "@angular/core/testing";
+import {HierarchyTabComponent} from "./hierarchy-tab.component";
+import {ConfigureFn, configureTests} from "../../../../../../../../jest/test-config.helper";
+import {NO_ERRORS_SCHEMA} from "@angular/core";
+import {TranslateModule} from "../../../../../../shared/translator/translate.module";
+import {TopologyTemplateService} from "../../../../../../services/component-services/topology-template.service";
+import {WorkspaceService} from "../../../../workspace.service";
+import {ModulesService} from "../../../../../../services/modules.service";
+import {GlobalPipesModule} from "../../../../../../pipes/global-pipes.module";
+import {TranslateService} from "../../../../../../shared/translator/translate.service";
+import {ModalsHandler} from "../../../../../../../utils/modals-handler";
+import {ComponentFactory} from "../../../../../../../utils/component-factory";
+import {NgxsModule} from "@ngxs/store";
+import { SdcUiServices } from "onap-ui-angular";
+import {Observable} from "rxjs";
+import {DisplayModule, Module} from "../../../../../../../models/modules/base-module";
+import {DeploymentGraphService} from "../../../../../composition/deployment/deployment-graph.service";
+import {ComponentMetadata} from "../../../../../../../models/component-metadata";
+
+describe('HierarchyTabComponent', () => {
+
+ let fixture: ComponentFixture<HierarchyTabComponent>;
+ let workspaceService: Partial<WorkspaceService>;
+ let popoverServiceMock: Partial<SdcUiServices.PopoverService>;
+ let modulesServiceMock: Partial<ModulesService>;
+
+ let editModuleNameInstanceMock = {innerPopoverContent:{instance: { clickButtonEvent: Observable.of("new heat name")}},
+ closePopover: jest.fn()};
+ let eventMock = {x: 1650, y: 350};
+ let moduleMock: Array<Module> = [{name: "NewVf2..base_vepdg..module-0", uniqueId: '1'}];
+ let selectedModuleMock: DisplayModule = {name: "NewVf2..base_vepdg..module-0", vfInstanceName: "NewVf2", moduleName:"module-0",
+ heatName: "base_vepdg", uniqueId: '1', updateName: jest.fn().mockImplementation(() => {
+ selectedModuleMock.name = selectedModuleMock.vfInstanceName + '..' + selectedModuleMock.heatName + '..' +
+ selectedModuleMock.moduleName;})}
+ let updateSelectedModuleMock = () => {
+ selectedModuleMock.heatName = "base_vepdg";
+ selectedModuleMock.name = "NewVf2..base_vepdg..module-0";
+ fixture.componentInstance.selectedModule = selectedModuleMock;
+ fixture.componentInstance.modules = moduleMock;
+ }
+ beforeEach(
+ async(() => {
+
+ workspaceService ={
+ metadata: <ComponentMetadata> {
+ name: '',
+ componentType: ''
+ }
+ }
+ popoverServiceMock = {
+ createPopOverWithInnerComponent: jest.fn().mockImplementation(() => {return editModuleNameInstanceMock})
+ }
+ modulesServiceMock = {
+ updateModuleMetadata: jest.fn().mockReturnValue(Observable.of({}))
+ }
+
+ const configure: ConfigureFn = testBed => {
+ testBed.configureTestingModule({
+ declarations: [HierarchyTabComponent],
+ schemas: [NO_ERRORS_SCHEMA],
+ imports: [TranslateModule, NgxsModule.forRoot([]), GlobalPipesModule],
+ providers: [
+ {provide: DeploymentGraphService, useValue: {}},
+ {provide: ComponentFactory, useValue: {}},
+ {provide: TopologyTemplateService, useValue: {}},
+ {provide: WorkspaceService, useValue: workspaceService},
+ {provide: ModulesService, useValue: modulesServiceMock},
+ {provide: TranslateService, useValue: {}},
+ {provide: ModalsHandler, useValue: {}},
+ {provide: SdcUiServices.PopoverService, useValue: popoverServiceMock}
+ ]
+ });
+ };
+
+ configureTests(configure).then(testBed => {
+ fixture = testBed.createComponent(HierarchyTabComponent);
+ });
+ })
+ );
+
+ it('expected heirarchy component to be defined', () => {
+ expect(fixture).toBeDefined();
+ });
+
+ it('Update heat name and name sucessfully', () => {
+ updateSelectedModuleMock();
+ fixture.componentInstance.openEditModuleNamePopup(eventMock);
+ expect(fixture.componentInstance.selectedModule.updateName).toHaveBeenCalled();
+ expect(modulesServiceMock.updateModuleMetadata).toHaveBeenCalled();
+ expect(fixture.componentInstance.selectedModule.name).toEqual('NewVf2..new heat name..module-0');
+ expect(fixture.componentInstance.modules[0].name).toEqual('NewVf2..new heat name..module-0');
+ expect(fixture.componentInstance.selectedModule.heatName).toEqual('new heat name');
+ })
+ it('Try to update heat name and name and get error from server', () => {
+ updateSelectedModuleMock();
+ modulesServiceMock.updateModuleMetadata.mockImplementation(() => Observable.throwError({}));
+ fixture.componentInstance.openEditModuleNamePopup(eventMock);
+ expect(fixture.componentInstance.selectedModule.updateName).toHaveBeenCalled();
+ expect(modulesServiceMock.updateModuleMetadata).toHaveBeenCalled();
+ expect(fixture.componentInstance.modules[0].name).toEqual('NewVf2..base_vepdg..module-0');
+ expect(fixture.componentInstance.selectedModule.heatName).toEqual('base_vepdg');
+ expect(fixture.componentInstance.selectedModule.name).toEqual('NewVf2..base_vepdg..module-0');
+ })
+ it('Try to update heat name and name but not find the module with the same uniqueId', () => {
+ selectedModuleMock.uniqueId = '2'
+ updateSelectedModuleMock();
+ fixture.componentInstance.openEditModuleNamePopup(eventMock);
+ expect(fixture.componentInstance.selectedModule.updateName).toHaveBeenCalled();
+ expect(modulesServiceMock.updateModuleMetadata).not.toHaveBeenCalled();
+ expect(fixture.componentInstance.modules[0].name).toEqual('NewVf2..base_vepdg..module-0');
+ expect(fixture.componentInstance.selectedModule.heatName).toEqual('base_vepdg');
+ expect(fixture.componentInstance.selectedModule.name).toEqual('NewVf2..base_vepdg..module-0');
+ selectedModuleMock.uniqueId = '1'
+ })
+ it('Open edit module name popover and change the heat name', () => {
+ updateSelectedModuleMock();
+ spyOn(fixture.componentInstance, 'updateHeatName');
+ spyOn(fixture.componentInstance, 'updateOriginalHeatName');
+ fixture.componentInstance.openEditModuleNamePopup(eventMock);
+ expect(popoverServiceMock.createPopOverWithInnerComponent).toHaveBeenCalled();
+ expect(fixture.componentInstance.selectedModule.heatName).toEqual("new heat name");
+ expect(fixture.componentInstance.updateHeatName).toHaveBeenCalled();
+ })
+
+
+ it('Open edit module name popover and not change the heat name', () => {
+ updateSelectedModuleMock();
+ editModuleNameInstanceMock.innerPopoverContent.instance.clickButtonEvent = Observable.of(null);
+ fixture.componentInstance.openEditModuleNamePopup(eventMock);
+ expect(popoverServiceMock.createPopOverWithInnerComponent).toHaveBeenCalled();
+ expect(fixture.componentInstance.selectedModule.heatName).toEqual("base_vepdg");
+ })
+}); \ No newline at end of file
diff --git a/catalog-ui/src/app/ng2/pages/workspace/deployment/panel/panel-tabs/hierarchy-tab/hierarchy-tab.component.ts b/catalog-ui/src/app/ng2/pages/workspace/deployment/panel/panel-tabs/hierarchy-tab/hierarchy-tab.component.ts
new file mode 100644
index 0000000000..604b194283
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/workspace/deployment/panel/panel-tabs/hierarchy-tab/hierarchy-tab.component.ts
@@ -0,0 +1,139 @@
+import {Component, Input} from "@angular/core";
+import {Component as TopologyTemplate, ComponentInstance, DisplayModule, Module, PropertyModel} from "app/models";
+import {TranslateService} from "app/ng2/shared/translator/translate.service";
+import {ComponentType} from "app/utils/constants";
+import {WorkspaceService} from "../../../../workspace.service";
+import {ModulesService} from "../../../../../../services/modules.service";
+import * as _ from "lodash";
+import {ModalsHandler} from "../../../../../../../utils/modals-handler";
+import {ComponentFactory} from "../../../../../../../utils/component-factory";
+import {Select, Store} from "@ngxs/store";
+import { SdcUiServices } from "onap-ui-angular";
+import { EditModuleName } from "../edit-module-name/edit-module-name.component";
+import {GraphState} from "../../../../../composition/common/store/graph.state";
+import {DeploymentGraphService} from "../../../../../composition/deployment/deployment-graph.service";
+import {OnSidebarOpenOrCloseAction} from "../../../../../composition/common/store/graph.actions";
+
+@ Component({
+ selector: 'hierarchy-tab',
+ templateUrl: './hierarchy-tab.component.html',
+ styleUrls: ['./hierarchy-tab.component.less'],
+})
+export class HierarchyTabComponent {
+
+ @Select(GraphState.withSidebar) withSidebar$: boolean;
+ @Input() isViewOnly: boolean;
+ public selectedIndex: number;
+ public selectedModule: DisplayModule;
+ public isLoading: boolean;
+ public topologyTemplateName: string;
+ public topologyTemplateType: string;
+ public modules: Array<Module> = [];
+ public componentInstances: Array<ComponentInstance> = [];
+ private editPropertyModalTopologyTemplate: TopologyTemplate;
+
+ constructor(private translateService: TranslateService,
+ private workspaceService: WorkspaceService,
+ private deploymentService: DeploymentGraphService,
+ private modulesService: ModulesService,
+ private ModalsHandler: ModalsHandler,
+ private componentFactory: ComponentFactory,
+ private store: Store,
+ private popoverService: SdcUiServices.PopoverService) {
+ this.isLoading = false;
+ this.topologyTemplateName = this.workspaceService.metadata.name;
+ this.topologyTemplateType = this.workspaceService.metadata.componentType;
+ }
+
+ ngOnInit() {
+ this.modules = this.deploymentService.modules;
+ this.componentInstances = this.deploymentService.componentInstances;
+ this.editPropertyModalTopologyTemplate = this.componentFactory.createEmptyComponent(this.topologyTemplateType);
+ this.editPropertyModalTopologyTemplate.componentInstances = this.deploymentService.componentInstances;
+ }
+
+ onModuleSelected(module: Module, componentInstanceId?: string): void {
+
+ let onSuccess = (module: DisplayModule) => {
+ console.log("Module Loaded: ", module);
+ this.selectedModule = module;
+ this.isLoading = false;
+ };
+
+ let onFailed = () => {
+ this.isLoading = false;
+ };
+
+ if (!this.selectedModule || (this.selectedModule && this.selectedModule.uniqueId != module.uniqueId)) {
+ this.isLoading = true;
+ if (this.topologyTemplateType == ComponentType.SERVICE) {
+ // this.selectedInstanceId = componentInstanceId;
+ this.modulesService.getComponentInstanceModule(this.topologyTemplateType, this.workspaceService.metadata.uniqueId, componentInstanceId, module.uniqueId).subscribe((resultModule: DisplayModule) => {
+ onSuccess(resultModule);
+ }, () => {
+ onFailed();
+ });
+ } else {
+ this.modulesService.getModuleForDisplay(this.topologyTemplateType, this.workspaceService.metadata.uniqueId, module.uniqueId).subscribe((resultModule: DisplayModule) => {
+ onSuccess(resultModule);
+ }, () => {
+ onFailed();
+ });
+ }
+ }
+ }
+
+ updateHeatName(): void {
+ this.isLoading = true;
+ let originalName: string = this.selectedModule.name;
+
+ this.selectedModule.updateName();
+ let moduleIndex: number = _.indexOf(this.modules, _.find(this.modules, (module: Module) => {
+ return module.uniqueId === this.selectedModule.uniqueId;
+ }));
+
+ if (moduleIndex !== -1) {
+ this.modules[moduleIndex].name = this.selectedModule.name;
+ this.modulesService.updateModuleMetadata(this.topologyTemplateType, this.workspaceService.metadata.uniqueId, this.modules[moduleIndex]).subscribe(() => {
+ this.isLoading = false;
+ }, () => {
+ this.updateOriginalHeatName(originalName, moduleIndex);
+ this.modules[moduleIndex].name = originalName;
+ });
+ } else {
+ this.updateOriginalHeatName(originalName, moduleIndex);
+ }
+ };
+
+ private updateOriginalHeatName(originalName: string, moduleIndex: number){
+ this.isLoading = false;
+ this.selectedModule.name = originalName;
+ this.selectedModule.heatName = this.selectedModule.name.split('..')[1];
+ }
+
+ openEditPropertyModal(property: PropertyModel): void {
+ this.editPropertyModalTopologyTemplate.setComponentMetadata(this.workspaceService.metadata);
+ this.ModalsHandler.openEditModulePropertyModal(property, this.editPropertyModalTopologyTemplate, this.selectedModule, this.selectedModule.properties).then(() => {
+ });
+ }
+
+ private getKeys(map: Map<any, any>) {
+ return _.keys(map);
+ }
+
+ private toggleSidebarDisplay = () => {
+ // this.withSidebar = !this.withSidebar;
+ this.store.dispatch(new OnSidebarOpenOrCloseAction());
+ }
+
+ public openEditModuleNamePopup($event) {
+ const editModuleNameInstance = this.popoverService.createPopOverWithInnerComponent('Edit Module Name', '', {x:$event.x , y:$event.y }, EditModuleName, {selectModule: _.cloneDeep(this.selectedModule)}, 'top');
+ editModuleNameInstance.innerPopoverContent.instance.clickButtonEvent.subscribe((newHeatName) => {
+ if(newHeatName != null){
+ this.selectedModule.heatName = newHeatName;
+ this.updateHeatName();
+ }
+ editModuleNameInstance.closePopover();
+ })
+ }
+}
diff --git a/catalog-ui/src/app/ng2/pages/workspace/deployment/panel/panel-tabs/hierarchy-tab/hierarchy-tab.module.ts b/catalog-ui/src/app/ng2/pages/workspace/deployment/panel/panel-tabs/hierarchy-tab/hierarchy-tab.module.ts
new file mode 100644
index 0000000000..048ca0c65f
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/workspace/deployment/panel/panel-tabs/hierarchy-tab/hierarchy-tab.module.ts
@@ -0,0 +1,24 @@
+/**
+ * Created by ob0695 on 6/4/2018.
+ */
+import {NgModule} from "@angular/core";
+import {SdcUiComponentsModule} from "onap-ui-angular";
+import {HierarchyTabComponent} from "./hierarchy-tab.component";
+import {UiElementsModule} from "../../../../../../components/ui/ui-elements.module";
+import {TranslateModule} from "../../../../../../shared/translator/translate.module";
+import {CommonModule} from "@angular/common";
+import {GlobalPipesModule} from "../../../../../../pipes/global-pipes.module";
+import { EditModuleName } from "../edit-module-name/edit-module-name.component";
+
+@NgModule({
+ declarations: [HierarchyTabComponent, EditModuleName],
+ imports: [CommonModule,
+ UiElementsModule,
+ SdcUiComponentsModule,
+ TranslateModule,
+ GlobalPipesModule],
+ entryComponents: [HierarchyTabComponent, EditModuleName],
+ exports: [HierarchyTabComponent, EditModuleName],
+})
+export class HierarchyTabModule {
+} \ No newline at end of file