diff options
author | imamSidero <imam.hussain@est.tech> | 2023-08-24 11:48:06 +0100 |
---|---|---|
committer | Michael Morris <michael.morris@est.tech> | 2023-09-04 14:21:30 +0000 |
commit | 0c47a1b7118b45eecbbb0064b635efb026173ec4 (patch) | |
tree | 863e35ed75b70a5f27f632b95bf8d7b38c437d72 | |
parent | b945edb543cc7283908a019bd8859ad936572e86 (diff) |
Provide UI page for interface assignment in service for VFC instances
Support for interface assignment page for VFC instances is provided in service instances
Issue-ID: SDC-4602
Signed-off-by: Imam hussain <imam.hussain@est.tech>
Change-Id: I4cabef02db381278d37d21da981d3ec4c04e5967
6 files changed, 246 insertions, 69 deletions
diff --git a/catalog-ui/configurations/menu.js b/catalog-ui/configurations/menu.js index a5114d857a..54c1b63d7d 100644 --- a/catalog-ui/configurations/menu.js +++ b/catalog-ui/configurations/menu.js @@ -297,6 +297,7 @@ const SDC_MENU_CONFIG = { {"text": "Network Call Flow ", "action": "onMenuItemPressed", "state": "workspace.network_call_flow"}, {"text": "Distribution","action": "onMenuItemPressed","state": "workspace.distribution","disabledRoles": ["ADMIN"]}, {"text": "Deployment", "action": "onMenuItemPressed", "state": "workspace.deployment"}, + {"text": "Interfaces Assignment", "action": "onMenuItemPressed", "state": "workspace.interface-definition"}, {"text": "Properties Assignment", "action": "onMenuItemPressed", "state": "workspace.properties_assignment"}, {"text": "Attributes & Outputs", "action": "onMenuItemPressed", "state": "workspace.attributes_outputs"} ], diff --git a/catalog-ui/src/app/ng2/pages/interface-definition/interface-definition.module.ts b/catalog-ui/src/app/ng2/pages/interface-definition/interface-definition.module.ts index 27a7f111d2..ea6279ec87 100644 --- a/catalog-ui/src/app/ng2/pages/interface-definition/interface-definition.module.ts +++ b/catalog-ui/src/app/ng2/pages/interface-definition/interface-definition.module.ts @@ -24,6 +24,7 @@ import {UiElementsModule} from "app/ng2/components/ui/ui-elements.module"; import {TranslateModule} from "app/ng2/shared/translator/translate.module"; import { SdcUiComponentsModule } from 'onap-ui-angular'; import {InterfaceDefinitionComponent} from "./interface-definition.page.component"; +import {HierarchyNavigationModule} from "../../components/logic/hierarchy-navigtion/hierarchy-navigation.module"; import {InterfaceOperationHandlerModule} from "../composition/interface-operatons/operation-creator/interface-operation-handler.module"; @NgModule({ @@ -34,6 +35,7 @@ import {InterfaceOperationHandlerModule} from "../composition/interface-operaton CommonModule, SdcUiComponentsModule, UiElementsModule, + HierarchyNavigationModule, TranslateModule, InterfaceOperationHandlerModule ], diff --git a/catalog-ui/src/app/ng2/pages/interface-definition/interface-definition.page.component.html b/catalog-ui/src/app/ng2/pages/interface-definition/interface-definition.page.component.html index bf36df0593..15fe65a784 100644 --- a/catalog-ui/src/app/ng2/pages/interface-definition/interface-definition.page.component.html +++ b/catalog-ui/src/app/ng2/pages/interface-definition/interface-definition.page.component.html @@ -19,73 +19,92 @@ --> <div class="interface-definition"> <loader [display]="isLoading" [size]="'large'" [relative]="true"></loader> - <div *ngIf="isInterfaceListEmpty()"> - <div class="interface-empty-msg"> - <div>{{ 'INTERFACE_DATA_EMPTY' | translate }}</div> + <div class="left-column"> + <div *ngIf="isInterfaceListEmpty()"> + <div class="interface-empty-msg"> + <div>{{ 'INTERFACE_DATA_EMPTY' | translate }}</div> + </div> </div> - </div> - <div - class="top-add-btn add-btn" - [ngClass]="{'disabled': readonly}" - data-tests-id="add-operation" - (click)="onSelectInterfaceOperation(undefined, undefined)"> + <div class="top-add-btn add-btn" [ngClass]="{'disabled': readonly}" *ngIf="!component.isService()" data-tests-id="add-operation" (click)="onSelectInterfaceOperation(undefined, undefined)"> {{ 'INTERFACE_ADD_OPERATION' | translate }} - </div> - <div class="operation-list"> - <div *ngIf="!isInterfaceListEmpty()"> - <div class="expand-collapse" *ngIf="isOperationListEmpty()"> - <a class="link" - [ngClass]="{'disabled': isAllExpanded()}" - (click)="collapseAll(false)">{{ 'INTERFACE_EXPAND_ALL' | translate }} - </a> | - <a class="link" - [ngClass]="{'disabled': isAllCollapsed()}" - (click)="collapseAll()"> - {{ 'INTERFACE_COLLAPSE_ALL' | translate }} - </a> - </div> - - <div class="interface-row" *ngFor="let interface1 of interfaces"> - <div class="interface-accordion" (click)="interface1.toggleCollapse()"> - <span - class="chevron-container" - [ngClass]="{'isCollapsed': interface1.isCollapsed}" - *ngIf="isOperationListEmpty()"> - <svg-icon - name="caret1-down-o" - mode="primary" - size="small"> - </svg-icon> - </span> - <span class="interface-name">{{interface1.type}}</span> + </div> + <div class="operation-list"> + <div *ngIf="!isInterfaceListEmpty()"> + <div class="expand-collapse" *ngIf="isOperationListEmpty()"> + <a class="link" + [ngClass]="{'disabled': isAllExpanded()}" + (click)="collapseAll(false)">{{ 'INTERFACE_EXPAND_ALL' | translate }} + </a> | + <a class="link" + [ngClass]="{'disabled': isAllCollapsed()}" + (click)="collapseAll()"> + {{ 'INTERFACE_COLLAPSE_ALL' | translate }} + </a> </div> - <div class="generic-table" *ngIf="!interface1.isCollapsed && isOperationListEmpty()"> - <div class="header-row table-row"> + <div class="interface-row" *ngFor="let interface1 of interfaces"> + <div class="interface-accordion" (click)="interface1.toggleCollapse()"> <span - class="cell header-cell field-name header-name"> - {{ 'INTERFACE_HEADER_NAME' | translate }} + class="chevron-container" + [ngClass]="{'isCollapsed': interface1.isCollapsed}" + *ngIf="isOperationListEmpty()"> + <svg-icon + name="caret1-down-o" + mode="primary" + size="small"> + </svg-icon> </span> - <span class="cell header-cell field-description header-description"> - {{ 'INTERFACE_HEADER_DESCRIPTION' | translate }} - </span> - <span class="cell field-delete" *ngIf="!readonly"><span class="delete-col-header"></span></span> + <span class="interface-name">{{interface1.type}}</span> </div> - <div class="data-row" *ngFor="let operation of interface1.operations"> - <span class="cell field-name" - (click)="onSelectInterfaceOperation(interface1, operation)">{{operation.name}}</span> - <span class="cell field-description" (click)="onSelectInterfaceOperation(interface1, operation)" - [ngClass]="{'collapsed': operation.isCollapsed}">{{operation.getDescriptionEllipsis()}} - <span class="more-or-less link" (click)="operation.toggleCollapsed($event)"> - {{!operation.isEllipsis ? '' : operation.isCollapsed ? 'More' : 'Less'}} + + <div class="generic-table" *ngIf="!interface1.isCollapsed && isOperationListEmpty()"> + <div class="header-row table-row"> + <span + class="cell header-cell field-name header-name"> + {{ 'INTERFACE_HEADER_NAME' | translate }} </span> - </span> - <span class="cell field-delete" *ngIf="!readonly"> - <button class="table-delete-btn" (click)="onRemoveOperation(operation)"></button> - </span> + <span class="cell header-cell field-description header-description"> + {{ 'INTERFACE_HEADER_DESCRIPTION' | translate }} + </span> + <span class="cell field-delete" *ngIf="!readonly"><span class="delete-col-header"></span></span> + </div> + <div class="data-row" *ngFor="let operation of interface1.operations"> + <span class="cell field-name" + (click)="onSelectInterfaceOperation(interface1, operation)">{{operation.name}}</span> + <span class="cell field-description" (click)="onSelectInterfaceOperation(interface1, operation)" + [ngClass]="{'collapsed': operation.isCollapsed}">{{operation.getDescriptionEllipsis()}} + <span class="more-or-less link" (click)="operation.toggleCollapsed($event)"> + {{!operation.isEllipsis ? '' : operation.isCollapsed ? 'More' : 'Less'}} + </span> + </span> + <span class="cell field-delete" *ngIf="!readonly"> + <button class="table-delete-btn" (click)="onRemoveOperation(operation)"></button> + </span> + </div> </div> </div> </div> </div> </div> + <div class="right-column" *ngIf="component.isService()"> + <div class="add-btn" [ngClass]="{'disabled': disableFlag}" data-tests-id="add-operation" (click)="onSelectInterfaceOperation(undefined, undefined)"> + {{ 'INTERFACE_ADD_OPERATION' | translate }} + </div> + <tabs #hierarchyNavTabs tabStyle="simple-tabs" class="gray-border"> + <tab tabTitle="Composition"> + <div class="hierarchy-nav-container"> + <loader [display]="loadingInstances" [size]="'medium'" [relative]="true" [loaderDelay]="500"></loader> + <div class="hierarchy-header white-sub-header"> + <span tooltip="{{component.name}}">{{component.name}}</span> + </div> + <div *ngIf="!instancesNavigationData || instancesNavigationData.length === 0">No data to display</div> + <hierarchy-navigation class="hierarchy-nav" + (updateSelected)="onInstanceSelectedUpdate($event)" + [displayData]="instancesNavigationData" + [selectedItem]="selectedInstanceData?.uniqueId" + [displayOptions]="hierarchyInstancesDisplayOptions"></hierarchy-navigation> + </div> + </tab> + </tabs> + </div> </div> diff --git a/catalog-ui/src/app/ng2/pages/interface-definition/interface-definition.page.component.less b/catalog-ui/src/app/ng2/pages/interface-definition/interface-definition.page.component.less index 464732e016..67e2dae2e1 100644 --- a/catalog-ui/src/app/ng2/pages/interface-definition/interface-definition.page.component.less +++ b/catalog-ui/src/app/ng2/pages/interface-definition/interface-definition.page.component.less @@ -23,7 +23,9 @@ @import '../../../../assets/styles/sprite-old.less'; .interface-definition { font-size: 14px; - + display:flex; + flex-direction:row; + height: 100%; .delete-col-header{ .sprite; .sprite.e-sdc-small-icon-delete; @@ -53,14 +55,6 @@ padding: 14px; } - .top-add-btn { - position: relative; - top: -31px; - text-transform: uppercase; - font-size: 14px; - font-family: @font-opensans-medium; - } - .link { color: @sdcui_color_blue; text-decoration: underline; @@ -79,7 +73,7 @@ .operation-list { border-top: 1px solid @main_color_o; padding-top: 5px; - + .empty-list-container { width: 100%; display: flex; @@ -250,4 +244,86 @@ } } + .left-column { + flex: 1 0 500px; + position: relative; + min-width:930px; + } + .right-column { + display:flex; + flex:0 0 350px; + flex-direction:column; + margin: 0px 0 0 1em; + overflow-x:auto; + .add-btn{ + align-self: flex-end; + margin-top: 10px; + margin-bottom: 19px; + } + /deep/ .tabs { + border-bottom: solid 1px #d0d0d0; + } + + /deep/ .tab { + flex: none; + padding: 8px 20px 0; + font-size: 14px; + line-height:30px; + font-family: @font-opensans-regular; + + &.active { + font-family: @font-opensans-medium; + } + } + } + + .hierarchy-tabs { + flex: 0 0 40px; + } + + .gray-border { + border: 1px solid #ddd; + } + + /deep/ .white-sub-header { + background-color: #fffefe; + box-shadow: 0px 1px 0.99px 0.01px rgba(34, 31, 31, 0.15); + border-bottom: #d2d2d2 solid 1px; + font-size:14px; + text-align:left; + flex:0 0 auto; + padding: 10px; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + text-transform: uppercase; + + &.hierarchy-header { + padding-left:20px; + &.selected { + background-color: #e6f6fb; + } + } + + } + + .hierarchy-header { + + span{ + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + max-width: 290px; + } + } + + .hierarchy-nav { + flex:1; + overflow:auto; + display: grid; + margin-top: 1em; + margin-left: 1em; + font-size: 12px; + padding-top: 1em; + } } diff --git a/catalog-ui/src/app/ng2/pages/interface-definition/interface-definition.page.component.ts b/catalog-ui/src/app/ng2/pages/interface-definition/interface-definition.page.component.ts index 90d6a6cfde..23c855ecb1 100644 --- a/catalog-ui/src/app/ng2/pages/interface-definition/interface-definition.page.component.ts +++ b/catalog-ui/src/app/ng2/pages/interface-definition/interface-definition.page.component.ts @@ -21,7 +21,7 @@ import {Component, ComponentRef, Inject, Input} from '@angular/core'; import {Component as IComponent} from 'app/models/components/component'; import {WorkflowServiceNg2} from 'app/ng2/services/workflow.service'; - +import {HierarchyDisplayOptions} from "../../components/logic/hierarchy-navigtion/hierarchy-display-options"; import {ISdcConfig, SdcConfigToken} from "app/ng2/config/sdc-config.config"; import {TranslateService} from "app/ng2/shared/translator/translate.service"; import {IModalButtonComponent, SdcUiServices} from 'onap-ui-angular'; @@ -34,6 +34,7 @@ import { CapabilitiesGroup, InputBEModel, InterfaceModel, + ComponentInstance, ModalModel, OperationModel, WORKFLOW_ASSOCIATION_OPTIONS @@ -49,6 +50,7 @@ import {ToscaArtifactService} from "../../services/tosca-artifact.service"; import {InterfaceOperationComponent} from "../interface-operation/interface-operation.page.component"; import {Observable} from "rxjs/Observable"; import {PluginsService} from 'app/ng2/services/plugins.service'; +import { InstanceFeDetails } from 'app/models/instance-fe-details'; export class UIOperationModel extends OperationModel { isCollapsed: boolean = true; @@ -132,6 +134,13 @@ export class InterfaceDefinitionComponent { interfaces: UIInterfaceModel[]; inputs: InputBEModel[]; + instancesNavigationData = []; + instances: any = []; + loadingInstances: boolean = false; + selectedInstanceData: any = null; + hierarchyInstancesDisplayOptions: HierarchyDisplayOptions = new HierarchyDisplayOptions('uniqueId', 'name', 'archived', null, 'iconClass'); + disableFlag : boolean = true; + deploymentArtifactsFilePath: Array<DropdownValue> = []; toscaArtifactTypes: Array<DropdownValue> = []; @@ -148,6 +157,7 @@ export class InterfaceDefinitionComponent { enableWorkflowAssociation: boolean; workflowIsOnline: boolean; validImplementationProps:boolean = true; + serviceInterfaces: InterfaceModel[]; @Input() component: IComponent; @Input() readonly: boolean; @@ -176,21 +186,39 @@ export class InterfaceDefinitionComponent { ngOnInit(): void { this.isLoading = true; this.interfaces = []; + //this.disableFlag = this.readonly; this.workflowIsOnline = !_.isUndefined(this.PluginsService.getPluginByStateUrl('workflowDesigner')); Observable.forkJoin( this.ComponentServiceNg2.getInterfaceOperations(this.component), this.ComponentServiceNg2.getComponentInputs(this.component), this.ComponentServiceNg2.getInterfaceTypes(this.component), - this.ComponentServiceNg2.getCapabilitiesAndRequirements(this.component.componentType, this.component.uniqueId) + this.ComponentServiceNg2.getCapabilitiesAndRequirements(this.component.componentType, this.component.uniqueId), + this.componentServiceNg2.getComponentResourcePropertiesData(this.component) ).subscribe((response: any[]) => { const callback = (workflows) => { this.isLoading = false; + this.serviceInterfaces = response[0].interfaces; this.initInterfaces(response[0].interfaces); this.sortInterfaces(); this.inputs = response[1].inputs; this.interfaceTypes = response[2]; this.workflows = (workflows.items) ? workflows.items : workflows; this.capabilities = response[3].capabilities; + this.instances = response[4].componentInstances; + const serviceInstance = new ComponentInstance(); + serviceInstance.name = "SELF"; + serviceInstance.uniqueId = this.component.uniqueId; + if (this.instances != null) { + this.instances.unshift(serviceInstance); + } else { + this.instances = [serviceInstance]; + } + _.forEach(this.instances, (instance) => { + this.instancesNavigationData.push(instance); + }); + this.onInstanceSelectedUpdate(this.instancesNavigationData[0]); + this.loadingInstances = false; + }; if (this.enableWorkflowAssociation && this.workflowIsOnline) { this.WorkflowServiceNg2.getWorkflows().subscribe( @@ -204,9 +232,55 @@ export class InterfaceDefinitionComponent { callback([]); } }); + this.loadToscaArtifacts(); } + onInstanceSelectedUpdate = (instance: any) => { + this.selectedInstanceData = instance; + if (instance.name != "SELF") { + this.disableFlag = true; + let newInterfaces : InterfaceModel[] = []; + if (instance.interfaces instanceof Array) { + instance.interfaces.forEach(result => { + let interfaceObj = new InterfaceModel(); + interfaceObj.type = result.type; + interfaceObj.uniqueId = result.uniqueId; + if (result.operations instanceof Array) { + interfaceObj.operations = result.operations; + } else if (!_.isEmpty(result.operations)) { + interfaceObj.operations = []; + Object.keys(result.operations).forEach(name => { + interfaceObj.operations.push(result.operations[name]); + }); + } + newInterfaces.push(interfaceObj); + }); + } else { + Object.keys(instance.interfaces).forEach(key => { + let obj = instance.interfaces[key]; + let interfaceObj = new InterfaceModel(); + interfaceObj.type = obj.type; + interfaceObj.uniqueId = obj.uniqueId; + if (obj.operations instanceof Array) { + interfaceObj.operations = obj.operations; + } else if (!_.isEmpty(obj.operations)) { + interfaceObj.operations = []; + Object.keys(obj.operations).forEach(name => { + interfaceObj.operations.push(obj.operations[name]); + }); + } + newInterfaces.push(interfaceObj); + }); + } + this.interfaces = newInterfaces.map((interf) => new UIInterfaceModel(interf)); + } else { + //this.disableFlag = this.readonly; + this.interfaces = this.serviceInterfaces.map((interf) => new UIInterfaceModel(interf)); + } + this.sortInterfaces(); + } + initInterfaces(interfaces: InterfaceModel[]): void { if (interfaces) { this.interfaces = interfaces.map((interf) => new UIInterfaceModel(interf)); @@ -222,6 +296,9 @@ export class InterfaceDefinitionComponent { if(this.readonly) { return disable; } + if (this.component.isService()) { + return disable; + } let selectedInterfaceOperation = this.modalInstance.instance.dynamicContent.instance.selectedInterfaceOperation; let isInterfaceOperation:boolean = !(typeof selectedInterfaceOperation == 'undefined' || _.isEmpty(selectedInterfaceOperation)); diff --git a/catalog-ui/src/app/ng2/services/component-services/component.service.ts b/catalog-ui/src/app/ng2/services/component-services/component.service.ts index 450e66ead2..eca70bee5f 100644 --- a/catalog-ui/src/app/ng2/services/component-services/component.service.ts +++ b/catalog-ui/src/app/ng2/services/component-services/component.service.ts @@ -114,7 +114,7 @@ export class ComponentServiceNg2 { } getComponentResourcePropertiesData(component: Component): Observable<ComponentGenericResponse> { - return this.getComponentDataByFieldsName(component.componentType, component.uniqueId, [COMPONENT_FIELDS.COMPONENT_INSTANCES, COMPONENT_FIELDS.COMPONENT_POLICIES, COMPONENT_FIELDS.COMPONENT_NON_EXCLUDED_GROUPS]); + return this.getComponentDataByFieldsName(component.componentType, component.uniqueId, [COMPONENT_FIELDS.COMPONENT_INSTANCES, COMPONENT_FIELDS.COMPONENT_INTERFACE_OPERATIONS, COMPONENT_FIELDS.COMPONENT_POLICIES, COMPONENT_FIELDS.COMPONENT_NON_EXCLUDED_GROUPS]); } getComponentResourceAttributesData(component: Component): Observable<ComponentGenericResponse> { @@ -157,6 +157,8 @@ export class ComponentServiceNg2 { return this.getComponentDataByFieldsName(component.componentType, component.uniqueId, [COMPONENT_FIELDS.COMPONENT_INTERFACE_OPERATIONS]); } + + getInterfaceOperation(component: Component, operation: OperationModel): Observable<OperationModel> { return this.http.get<OperationModel>(this.baseUrl + component.getTypeUrl() + component.uniqueId + '/interfaceOperations/' + operation.uniqueId); } |