diff options
author | vasraz <vasyl.razinkov@est.tech> | 2021-02-16 17:37:57 +0000 |
---|---|---|
committer | Christophe Closset <christophe.closset@intl.att.com> | 2021-02-17 15:57:55 +0000 |
commit | 26e5029d922779fd7e786c1a31b6b37492132388 (patch) | |
tree | 8e8e68a6913749e1405fce951bc7816d4fa35ba3 /catalog-ui/src/app/ng2/pages/workspace | |
parent | f2c0a4118c3c0b6360b639622766543bd754b59c (diff) |
Implement Attributes/Outputs FE
Change-Id: I014bb0ebc07f3fea4266a4f295172eadee546705
Signed-off-by: Vasyl Razinkov <vasyl.razinkov@est.tech>
Issue-ID: SDC-3448
Diffstat (limited to 'catalog-ui/src/app/ng2/pages/workspace')
6 files changed, 2 insertions, 501 deletions
diff --git a/catalog-ui/src/app/ng2/pages/workspace/attributes/attribute-modal.component.ts b/catalog-ui/src/app/ng2/pages/workspace/attributes/attribute-modal.component.ts index b0a7651809..426ed4063e 100644 --- a/catalog-ui/src/app/ng2/pages/workspace/attributes/attribute-modal.component.ts +++ b/catalog-ui/src/app/ng2/pages/workspace/attributes/attribute-modal.component.ts @@ -11,7 +11,7 @@ import { AttributeOptions } from './attributes-options'; @Component({ selector: 'attribute-modal', templateUrl: './attribute-modal.component.html', - styleUrls: ['./attributes.component.less'] + styleUrls: ['../../../../view-models/workspace/tabs/attributes/attributes.component.less'] }) export class AttributeModalComponent implements OnInit { diff --git a/catalog-ui/src/app/ng2/pages/workspace/attributes/attributes.component.html b/catalog-ui/src/app/ng2/pages/workspace/attributes/attributes.component.html deleted file mode 100644 index 6d50bbe11b..0000000000 --- a/catalog-ui/src/app/ng2/pages/workspace/attributes/attributes.component.html +++ /dev/null @@ -1,93 +0,0 @@ -<!-- - ~ Copyright (C) 2018 AT&T Intellectual Property. All rights reserved. - ~ - ~ 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. ---> -<div class="workspace-attributes"> - - <div class="action-bar-wrapper"> - <svg-icon-label - *ngIf="!(this.isViewOnly$ | async)" - class="add-attr-icon" - [name]="'plus'" - [mode]="'primary'" - [size]="'medium'" - [label]="'Add'" - [labelPlacement]="'right'" - [labelClassName]="'externalActionLabel'" - (click)="onAddAttribute()"> - </svg-icon-label> - </div> - - <ngx-datatable - columnMode="flex" - [footerHeight]="0" - [limit]="50" - [headerHeight]="40" - [rowHeight]="35" - [rows]="attributes" - #componentAttributesTable - (activate)="onExpandRow($event)"> - - <ngx-datatable-row-detail [rowHeight]="80"> - <ng-template let-row="row" let-expanded="expanded" ngx-datatable-row-detail-template> - <div>{{row.description}}</div> - </ng-template> - </ngx-datatable-row-detail> - - <ngx-datatable-column [resizeable]="false" name="Name" [flexGrow]="2"> - - <ng-template ngx-datatable-cell-template let-row="row" let-expanded="expanded"> - <div class="expand-collapse-cell"> - <svg-icon [clickable]="true" class="expand-collapse-icon" - [name]="expanded ? 'caret1-up-o': 'caret1-down-o'" [mode]="'primary'" - [size]="'medium'"></svg-icon> - <span>{{ row.name }}</span> - </div> - </ng-template> - - </ngx-datatable-column> - - <ngx-datatable-column [resizeable]="false" name="Type" [flexGrow]="1"> - <ng-template ngx-datatable-cell-template let-row="row"> - {{row.type}} - </ng-template> - </ngx-datatable-column> - - <ngx-datatable-column [resizeable]="false" name="Default Value" [flexGrow]="3"> - <ng-template ngx-datatable-cell-template let-row="row"> - {{row._default}} - </ng-template> - </ngx-datatable-column> - - <ngx-datatable-column *ngIf="!(this.isViewOnly$ | async)" [resizeable]="false" name="Action" [flexGrow]="1"> - <ng-template ngx-datatable-cell-template let-row="row" let-rowIndex="rowIndex"> - <div class="actionColumn"> - <svg-icon [clickable]="true" - [mode]="'primary2'" - [name]="'edit-o'" - [size]="'medium'" - (click)="onEditAttribute($event, row)"> - </svg-icon> - <svg-icon [clickable]="true" - [mode]="'primary2'" - [name]="'trash-o'" - (click)="onDeleteAttribute($event, row)" - [size]="'medium'"> - </svg-icon> - </div> - </ng-template> - </ngx-datatable-column> - - </ngx-datatable> -</div> diff --git a/catalog-ui/src/app/ng2/pages/workspace/attributes/attributes.component.less b/catalog-ui/src/app/ng2/pages/workspace/attributes/attributes.component.less deleted file mode 100644 index 3e91ae4689..0000000000 --- a/catalog-ui/src/app/ng2/pages/workspace/attributes/attributes.component.less +++ /dev/null @@ -1,36 +0,0 @@ -.action-bar-wrapper { - flex: 0 0 30%; - display: flex; - justify-content: flex-end; - margin-bottom: 10px; -} - -.add-attr-icon{ - cursor: pointer; -} - -.attr-container { - display: flex; - justify-content: space-between; - - .attr-col { - display: flex; - flex-direction: column; - max-width: 275px; - flex-grow: 1; - } - -} - -.attributeType { - margin-bottom: 10px; -} - -sdc-checkbox { - margin-top: 20px; -} - -.actionColumn { - text-align: center; - padding: 5px; -}
\ No newline at end of file diff --git a/catalog-ui/src/app/ng2/pages/workspace/attributes/attributes.component.spec.ts b/catalog-ui/src/app/ng2/pages/workspace/attributes/attributes.component.spec.ts deleted file mode 100644 index f676e2b4d9..0000000000 --- a/catalog-ui/src/app/ng2/pages/workspace/attributes/attributes.component.spec.ts +++ /dev/null @@ -1,182 +0,0 @@ -import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { async, ComponentFixture } from '@angular/core/testing'; -import { NgxDatatableModule } from '@swimlane/ngx-datatable'; -import { SdcUiCommon, SdcUiComponents, SdcUiServices } from 'onap-ui-angular'; -import 'rxjs/add/observable/of'; -import { Observable } from 'rxjs/Rx'; -import { ConfigureFn, configureTests } from '../../../../../jest/test-config.helper'; -import { ComponentMetadata } from '../../../../models/component-metadata'; -import { ModalsHandler } from '../../../../utils'; -import { TopologyTemplateService } from '../../../services/component-services/topology-template.service'; -import { TranslateService } from '../../../shared/translator/translate.service'; -import { WorkspaceService } from '../workspace.service'; -import { AttributesComponent } from './attributes.component'; - -describe('attributes component', () => { - - let fixture: ComponentFixture<AttributesComponent>; - - // Mocks - let workspaceServiceMock: Partial<WorkspaceService>; - let topologyTemplateServiceMock: Partial<TopologyTemplateService>; - let loaderServiceMock: Partial<SdcUiServices.LoaderService>; - let componentMetadataMock: ComponentMetadata; - let modalServiceMock: Partial<SdcUiServices.ModalService>; - - const mockAttributesList = [ - { uniqueId: '1', name: 'attr1', description: 'description1', type: 'string', hidden: false, defaultValue: 'val1', schema: null }, - { uniqueId : '2', name : 'attr2', description: 'description2', type : 'int', hidden : false, defaultValue : 1, schema : null}, - { uniqueId : '3', name : 'attr3', description: 'description3', type : 'double', hidden : false, defaultValue : 1.0, schema : null}, - { uniqueId : '4', name : 'attr4', description: 'description4', type : 'boolean', hidden : false, defaultValue : true, schema : null}, - ]; - - const newAttribute = { - uniqueId : '5', name : 'attr5', description: 'description5', type : 'string', hidden : false, defaultValue : 'val5', schema : null - }; - const updatedAttribute = { - uniqueId : '2', name : 'attr2', description: 'description_new', type : 'string', hidden : false, defaultValue : 'new_val2', schema : null - }; - const errorAttribute = { - uniqueId : '99', name : 'attr99', description: 'description_error', type : 'string', hidden : false, defaultValue : 'error', schema : null - }; - - beforeEach( - async(() => { - - componentMetadataMock = new ComponentMetadata(); - componentMetadataMock.uniqueId = 'fake'; - componentMetadataMock.componentType = 'VL'; - - topologyTemplateServiceMock = { - getComponentAttributes: jest.fn().mockResolvedValue({ attributes : mockAttributesList }), - addAttributeAsync: jest.fn().mockImplementation( - (compType, cUid, attr) => { - if (attr === errorAttribute) { - return Observable.throwError('add_error').toPromise(); - } else { - return Observable.of(newAttribute).toPromise(); - } - } - ), - updateAttributeAsync: jest.fn().mockImplementation( - (compType, cUid, attr) => { - if (attr === errorAttribute) { - return Observable.throwError('update_error').toPromise(); - } else { - return Observable.of(updatedAttribute).toPromise(); - } - } - ), - deleteAttributeAsync: jest.fn().mockImplementation((cid, ctype, attr) => Observable.of(attr)) - }; - - workspaceServiceMock = { - metadata: componentMetadataMock - }; - - const customModalInstance = { innerModalContent: { instance: { onValidationChange: { subscribe: jest.fn()}}}}; - - modalServiceMock = { - openInfoModal: jest.fn(), - openCustomModal: jest.fn().mockImplementation(() => customModalInstance) - }; - - loaderServiceMock = { - activate: jest.fn(), - deactivate: jest.fn() - }; - - const configure: ConfigureFn = (testBed) => { - testBed.configureTestingModule({ - declarations: [AttributesComponent], - imports: [NgxDatatableModule], - schemas: [NO_ERRORS_SCHEMA], - providers: [ - {provide: WorkspaceService, useValue: workspaceServiceMock}, - {provide: TopologyTemplateService, useValue: topologyTemplateServiceMock}, - {provide: ModalsHandler, useValue: {}}, - {provide: TranslateService, useValue: { translate: jest.fn() }}, - {provide: SdcUiServices.ModalService, useValue: modalServiceMock }, - {provide: SdcUiServices.LoaderService, useValue: loaderServiceMock } - ], - }); - }; - - configureTests(configure).then((testBed) => { - fixture = testBed.createComponent(AttributesComponent); - }); - }) - ); - - it('should see exactly 1 attributes on init', async () => { - await fixture.componentInstance.asyncInitComponent(); - expect(fixture.componentInstance.getAttributes().length).toEqual(4); - }); - - it('should see exactly 5 attributes when adding', async () => { - await fixture.componentInstance.asyncInitComponent(); - expect(fixture.componentInstance.getAttributes().length).toEqual(4); - - await fixture.componentInstance.addOrUpdateAttribute(newAttribute, false); - expect(fixture.componentInstance.getAttributes().length).toEqual(5); - }); - - it('should see exactly 3 attributes when deleting', async () => { - await fixture.componentInstance.asyncInitComponent(); - expect(fixture.componentInstance.getAttributes().length).toEqual(4); - const attrToDelete = mockAttributesList[0]; - expect(fixture.componentInstance.getAttributes().filter((attr) => attr.uniqueId === attrToDelete.uniqueId).length).toEqual(1); - await fixture.componentInstance.deleteAttribute(attrToDelete); - expect(fixture.componentInstance.getAttributes().length).toEqual(3); - expect(fixture.componentInstance.getAttributes().filter((attr) => attr.uniqueId === attrToDelete.uniqueId).length).toEqual(0); - }); - - it('should see updated attribute', async () => { - await fixture.componentInstance.asyncInitComponent(); - - await fixture.componentInstance.addOrUpdateAttribute(updatedAttribute, true); - expect(fixture.componentInstance.getAttributes().length).toEqual(4); - const attribute = fixture.componentInstance.getAttributes().filter( (attr) => { - return attr.uniqueId === updatedAttribute.uniqueId; - })[0]; - expect(attribute.description).toEqual( 'description_new'); - }); - - it('Add fails, make sure loader is deactivated and attribute is not added', async () => { - await fixture.componentInstance.asyncInitComponent(); - const numAttributes = fixture.componentInstance.getAttributes().length; - await fixture.componentInstance.addOrUpdateAttribute(errorAttribute, false); // Add - expect(loaderServiceMock.deactivate).toHaveBeenCalled(); - expect(fixture.componentInstance.getAttributes().length).toEqual(numAttributes); - }); - - it('Update fails, make sure loader is deactivated', async () => { - await fixture.componentInstance.asyncInitComponent(); - const numAttributes = fixture.componentInstance.getAttributes().length; - await fixture.componentInstance.addOrUpdateAttribute(errorAttribute, true); // Add - expect(loaderServiceMock.deactivate).toHaveBeenCalled(); - expect(fixture.componentInstance.getAttributes().length).toEqual(numAttributes); - }); - - it('on delete modal shell be opened', async () => { - await fixture.componentInstance.asyncInitComponent(); - const event = { stopPropagation: jest.fn() }; - fixture.componentInstance.onDeleteAttribute(event, fixture.componentInstance.getAttributes()[0]); - expect(event.stopPropagation).toHaveBeenCalled(); - expect(modalServiceMock.openInfoModal).toHaveBeenCalled(); - }); - - it('on add modal shell be opened', async () => { - await fixture.componentInstance.asyncInitComponent(); - fixture.componentInstance.onAddAttribute(); - expect(modalServiceMock.openCustomModal).toHaveBeenCalled(); - }); - - it('on edit modal shell be opened', async () => { - await fixture.componentInstance.asyncInitComponent(); - const event = { stopPropagation: jest.fn() }; - fixture.componentInstance.onEditAttribute(event, fixture.componentInstance.getAttributes()[0]); - expect(event.stopPropagation).toHaveBeenCalled(); - expect(modalServiceMock.openCustomModal).toHaveBeenCalled(); - }); -}); diff --git a/catalog-ui/src/app/ng2/pages/workspace/attributes/attributes.component.ts b/catalog-ui/src/app/ng2/pages/workspace/attributes/attributes.component.ts deleted file mode 100644 index bc47f1456b..0000000000 --- a/catalog-ui/src/app/ng2/pages/workspace/attributes/attributes.component.ts +++ /dev/null @@ -1,188 +0,0 @@ -import { Component, OnInit, ViewChild } from '@angular/core'; -import { Select } from '@ngxs/store'; -import { IAttributeModel } from 'app/models'; -import * as _ from 'lodash'; -import { SdcUiCommon, SdcUiComponents, SdcUiServices } from 'onap-ui-angular'; -import { ModalComponent } from 'onap-ui-angular/dist/modals/modal.component'; -import { AttributeModel } from '../../../../models'; -import { Resource } from '../../../../models'; -import { ModalsHandler } from '../../../../utils'; -import { TopologyTemplateService } from '../../../services/component-services/topology-template.service'; -import { TranslateService } from '../../../shared/translator/translate.service'; -import { WorkspaceState } from '../../../store/states/workspace.state'; -import { WorkspaceService } from '../workspace.service'; -import { AttributeModalComponent } from './attribute-modal.component'; - -@Component({ - selector: 'attributes', - templateUrl: './attributes.component.html', - styleUrls: ['./attributes.component.less', '../../../../../assets/styles/table-style.less'] -}) -export class AttributesComponent implements OnInit { - - @Select(WorkspaceState.isViewOnly) - isViewOnly$: boolean; - - @ViewChild('componentAttributesTable') - private table: any; - - private componentType: string; - private componentUid: string; - - private attributes: IAttributeModel[] = []; - private temp: IAttributeModel[] = []; - private customModalInstance: ModalComponent; - - constructor(private workspaceService: WorkspaceService, - private topologyTemplateService: TopologyTemplateService, - private modalsHandler: ModalsHandler, - private modalService: SdcUiServices.ModalService, - private loaderService: SdcUiServices.LoaderService, - private translateService: TranslateService) { - - this.componentType = this.workspaceService.metadata.componentType; - this.componentUid = this.workspaceService.metadata.uniqueId; - } - - ngOnInit(): void { - this.asyncInitComponent(); - } - - async asyncInitComponent() { - this.loaderService.activate(); - const response = await this.topologyTemplateService.getComponentAttributes(this.componentType, this.componentUid); - this.attributes = response.attributes; - this.temp = [...response.attributes]; - this.loaderService.deactivate(); - } - - getAttributes(): IAttributeModel[] { - return this.attributes; - } - - addOrUpdateAttribute = async (attribute: AttributeModel, isEdit: boolean) => { - this.loaderService.activate(); - let attributeFromServer: AttributeModel; - this.temp = [...this.attributes]; - - const deactivateLoader = () => { - this.loaderService.deactivate(); - return undefined; - }; - - if (isEdit) { - attributeFromServer = await this.topologyTemplateService - .updateAttributeAsync(this.componentType, this.componentUid, attribute) - .catch(deactivateLoader); - if (attributeFromServer) { - const indexOfUpdatedAttribute = _.findIndex(this.temp, (e) => e.uniqueId === attributeFromServer.uniqueId); - this.temp[indexOfUpdatedAttribute] = attributeFromServer; - } - } else { - attributeFromServer = await this.topologyTemplateService - .addAttributeAsync(this.componentType, this.componentUid, attribute) - .catch(deactivateLoader); - if (attributeFromServer) { - this.temp.push(attributeFromServer); - } - } - this.attributes = this.temp; - this.loaderService.deactivate(); - } - - deleteAttribute = async (attributeToDelete: AttributeModel) => { - this.loaderService.activate(); - this.temp = [...this.attributes]; - const res = await this.topologyTemplateService.deleteAttributeAsync(this.componentType, this.componentUid, attributeToDelete); - _.remove(this.temp, (attr) => attr.uniqueId === attributeToDelete.uniqueId); - this.attributes = this.temp; - this.loaderService.deactivate(); - }; - - openAddEditModal(selectedRow: AttributeModel, isEdit: boolean) { - const component = new Resource(undefined, undefined, undefined); - component.componentType = this.componentType; - component.uniqueId = this.componentUid; - - const title: string = this.translateService.translate('ATTRIBUTE_DETAILS_MODAL_TITLE'); - const attributeModalConfig = { - title, - size: 'md', - type: SdcUiCommon.ModalType.custom, - buttons: [ - { - id: 'save', - text: 'Save', - // spinner_position: Placement.left, - size: 'sm', - callback: () => this.modalCallBack(isEdit), - closeModal: true, - disabled: false, - } - ] as SdcUiCommon.IModalButtonComponent[] - }; - - this.customModalInstance = this.modalService.openCustomModal(attributeModalConfig, AttributeModalComponent, { attributeToEdit: selectedRow }); - this.customModalInstance.innerModalContent.instance. - onValidationChange.subscribe((isValid) => this.customModalInstance.getButtonById('save').disabled = !isValid); - } - - /*********************** - * Call Backs from UI * - ***********************/ - - /** - * Called when 'Add' is clicked - */ - onAddAttribute() { - this.openAddEditModal(new AttributeModel(), false); - } - - /** - * Called when 'Edit' button is clicked - */ - onEditAttribute(event, row) { - event.stopPropagation(); - - const attributeToEdit: AttributeModel = new AttributeModel(row); - this.openAddEditModal(attributeToEdit, true); - } - - /** - * Called when 'Delete' button is clicked - */ - onDeleteAttribute(event, row: AttributeModel) { - event.stopPropagation(); - const onOk = () => { - this.deleteAttribute(row); - }; - - const title: string = this.translateService.translate('ATTRIBUTE_VIEW_DELETE_MODAL_TITLE'); - const message: string = this.translateService.translate('ATTRIBUTE_VIEW_DELETE_MODAL_TEXT'); - const okButton = new SdcUiComponents.ModalButtonComponent(); - okButton.testId = 'OK'; - okButton.text = 'OK'; - okButton.type = SdcUiCommon.ButtonType.info; - okButton.closeModal = true; - okButton.callback = onOk; - - this.modalService.openInfoModal(title, message, 'delete-modal', [okButton]); - } - - onExpandRow(event) { - if (event.type === 'click') { - this.table.rowDetail.toggleExpandRow(event.row); - } - } - - /** - * Callback from Modal after "Save" is clicked - * - * @param {boolean} isEdit - Whether modal is edit or add attribute - */ - modalCallBack = (isEdit: boolean) => { - const attribute: AttributeModel = this.customModalInstance.innerModalContent.instance.attributeToEdit; - this.addOrUpdateAttribute(attribute, isEdit); - } - -} diff --git a/catalog-ui/src/app/ng2/pages/workspace/attributes/attributes.module.ts b/catalog-ui/src/app/ng2/pages/workspace/attributes/attributes.module.ts index 5abb952e37..f85d5298f9 100644 --- a/catalog-ui/src/app/ng2/pages/workspace/attributes/attributes.module.ts +++ b/catalog-ui/src/app/ng2/pages/workspace/attributes/attributes.module.ts @@ -2,7 +2,7 @@ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; import { SdcUiComponentsModule } from 'onap-ui-angular'; import { GlobalPipesModule } from '../../../pipes/global-pipes.module'; -import { AttributesComponent } from './attributes.component'; +import { AttributesComponent } from '../../../../view-models/workspace/tabs/attributes/attributes.component'; import { NgxDatatableModule } from '@swimlane/ngx-datatable'; import { TopologyTemplateService } from '../../../services/component-services/topology-template.service'; import { AttributeModalComponent } from './attribute-modal.component'; |