From 16a9fce0e104a38371a9e5a567ec611ae3fc7f33 Mon Sep 17 00:00:00 2001 From: ys9693 Date: Sun, 19 Jan 2020 13:50:02 +0200 Subject: Catalog alignment Issue-ID: SDC-2724 Signed-off-by: ys9693 Change-Id: I52b4aacb58cbd432ca0e1ff7ff1f7dd52099c6fe --- .../artifact-tab.component.spec.ts.snap | 50 ++++ .../artifacts-tab/artifact-tab.component.spec.ts | 303 +++++++++++++++++++++ .../artifacts-tab/artifacts-tab.component.html | 119 ++++++++ .../artifacts-tab/artifacts-tab.component.less | 169 ++++++++++++ .../artifacts-tab/artifacts-tab.component.ts | 204 ++++++++++++++ .../panel/panel-tabs/base/base-tab.component.less | 66 ----- .../group-members-tab.component.html | 47 ++++ .../group-members-tab.component.spec.ts | 127 +++++++++ .../group-members-tab.component.ts | 158 +++++++++++ .../group-or-policy-properties-tab.component.html | 39 +++ .../group-or-policy-properties-tab.component.ts | 52 ++++ .../groups/group-information-tab.component.html | 47 ---- .../groups/group-information-tab.component.ts | 39 --- .../groups/group-members-tab.component.html | 47 ---- .../groups/group-members-tab.component.less | 13 - .../groups/group-members-tab.component.ts | 133 --------- .../groups/group-properties-tab.component.html | 39 --- .../groups/group-properties-tab.component.less | 0 .../groups/group-properties-tab.component.ts | 64 ----- .../panel-tabs/groups/group-tabs.component.html | 27 -- .../panel-tabs/groups/group-tabs.component.ts | 67 ----- .../panel/panel-tabs/groups/group-tabs.module.ts | 71 ----- .../__snapshots__/info-tab.component.spec.ts.snap | 66 +++++ .../panel-tabs/info-tab/info-tab.component.html | 174 ++++++++++++ .../panel-tabs/info-tab/info-tab.component.less | 51 ++++ .../panel-tabs/info-tab/info-tab.component.spec.ts | 98 +++++++ .../panel-tabs/info-tab/info-tab.component.ts | 189 +++++++++++++ .../panel/panel-tabs/panel-tab.component.ts | 55 ++++ .../composition/panel/panel-tabs/panel-tabs.less | 65 +++++ .../policies/policy-information-tab.component.html | 50 ---- .../policies/policy-information-tab.component.ts | 39 --- .../policies/policy-properties-tab.component.html | 39 --- .../policies/policy-properties-tab.component.less | 0 .../policies/policy-properties-tab.component.ts | 64 ----- .../panel-tabs/policies/policy-tabs.component.html | 28 -- .../panel-tabs/policies/policy-tabs.component.ts | 72 ----- .../panel-tabs/policies/policy-tabs.module.ts | 68 ----- .../policies/policy-targets-tab.component.html | 48 ---- .../policies/policy-targets-tab.component.less | 12 - .../policies/policy-targets-tab.component.ts | 145 ---------- .../policy-targets-tab.component.html | 48 ++++ .../policy-targets-tab.component.less | 61 +++++ .../policy-targets-tab.component.spec.ts | 113 ++++++++ .../policy-targets-tab.component.ts | 166 +++++++++++ .../properties-tab/properties-tab.component.html | 97 +++++++ .../properties-tab/properties-tab.component.less | 66 +++++ .../properties-tab/properties-tab.component.ts | 212 ++++++++++++++ .../req-capabilities-tab.component.html | 36 +++ .../req-capabilities-tab.component.less | 57 ++++ .../req-capabilities-tab.component.ts | 165 +++++++++++ .../requirement-list.component.html | 20 ++ .../requirement-list/requirement-list.component.ts | 40 +++ .../service-consumption-tab.component.html | 15 + .../service-consumption-tab.component.less | 0 .../service-consumption-tab.component.ts | 89 ++++++ .../service-dependencies-tab.component.html | 18 ++ .../service-dependencies-tab.component.less | 3 + .../service-dependencies-tab.component.ts | 95 +++++++ 58 files changed, 3267 insertions(+), 1178 deletions(-) create mode 100644 catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/artifacts-tab/__snapshots__/artifact-tab.component.spec.ts.snap create mode 100644 catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/artifacts-tab/artifact-tab.component.spec.ts create mode 100644 catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/artifacts-tab/artifacts-tab.component.html create mode 100644 catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/artifacts-tab/artifacts-tab.component.less create mode 100644 catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/artifacts-tab/artifacts-tab.component.ts delete mode 100644 catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/base/base-tab.component.less create mode 100644 catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/group-members-tab/group-members-tab.component.html create mode 100644 catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/group-members-tab/group-members-tab.component.spec.ts create mode 100644 catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/group-members-tab/group-members-tab.component.ts create mode 100644 catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/group-or-policy-properties-tab/group-or-policy-properties-tab.component.html create mode 100644 catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/group-or-policy-properties-tab/group-or-policy-properties-tab.component.ts delete mode 100644 catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-information-tab.component.html delete mode 100644 catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-information-tab.component.ts delete mode 100644 catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-members-tab.component.html delete mode 100644 catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-members-tab.component.less delete mode 100644 catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-members-tab.component.ts delete mode 100644 catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-properties-tab.component.html delete mode 100644 catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-properties-tab.component.less delete mode 100644 catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-properties-tab.component.ts delete mode 100644 catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-tabs.component.html delete mode 100644 catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-tabs.component.ts delete mode 100644 catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-tabs.module.ts create mode 100644 catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/info-tab/__snapshots__/info-tab.component.spec.ts.snap create mode 100644 catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/info-tab/info-tab.component.html create mode 100644 catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/info-tab/info-tab.component.less create mode 100644 catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/info-tab/info-tab.component.spec.ts create mode 100644 catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/info-tab/info-tab.component.ts create mode 100644 catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/panel-tab.component.ts create mode 100644 catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/panel-tabs.less delete mode 100644 catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-information-tab.component.html delete mode 100644 catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-information-tab.component.ts delete mode 100644 catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-properties-tab.component.html delete mode 100644 catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-properties-tab.component.less delete mode 100644 catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-properties-tab.component.ts delete mode 100644 catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-tabs.component.html delete mode 100644 catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-tabs.component.ts delete mode 100644 catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-tabs.module.ts delete mode 100644 catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-targets-tab.component.html delete mode 100644 catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-targets-tab.component.less delete mode 100644 catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-targets-tab.component.ts create mode 100644 catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policy-targets-tab/policy-targets-tab.component.html create mode 100644 catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policy-targets-tab/policy-targets-tab.component.less create mode 100644 catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policy-targets-tab/policy-targets-tab.component.spec.ts create mode 100644 catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policy-targets-tab/policy-targets-tab.component.ts create mode 100644 catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/properties-tab/properties-tab.component.html create mode 100644 catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/properties-tab/properties-tab.component.less create mode 100644 catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/properties-tab/properties-tab.component.ts create mode 100644 catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/req-capabilities-tab/req-capabilities-tab.component.html create mode 100644 catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/req-capabilities-tab/req-capabilities-tab.component.less create mode 100644 catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/req-capabilities-tab/req-capabilities-tab.component.ts create mode 100644 catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/req-capabilities-tab/requirement-list/requirement-list.component.html create mode 100644 catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/req-capabilities-tab/requirement-list/requirement-list.component.ts create mode 100644 catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/service-consumption-tab/service-consumption-tab.component.html create mode 100644 catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/service-consumption-tab/service-consumption-tab.component.less create mode 100644 catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/service-consumption-tab/service-consumption-tab.component.ts create mode 100644 catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/service-dependencies-tab/service-dependencies-tab.component.html create mode 100644 catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/service-dependencies-tab/service-dependencies-tab.component.less create mode 100644 catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/service-dependencies-tab/service-dependencies-tab.component.ts (limited to 'catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs') diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/artifacts-tab/__snapshots__/artifact-tab.component.spec.ts.snap b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/artifacts-tab/__snapshots__/artifact-tab.component.spec.ts.snap new file mode 100644 index 0000000000..c143e8106b --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/artifacts-tab/__snapshots__/artifact-tab.component.spec.ts.snap @@ -0,0 +1,50 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`artifact-tab component should match current snapshot of artifact-tab component 1`] = ` + +
+
+ +
+ +
+ +
+ +
+ +
+
+
+
+
+`; diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/artifacts-tab/artifact-tab.component.spec.ts b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/artifacts-tab/artifact-tab.component.spec.ts new file mode 100644 index 0000000000..258f2295ab --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/artifacts-tab/artifact-tab.component.spec.ts @@ -0,0 +1,303 @@ +import { async, ComponentFixture } from '@angular/core/testing'; +import { ConfigureFn, configureTests } from '../../../../../../../jest/test-config.helper'; +import { NgxsModule, Store } from '@ngxs/store'; +import { WorkspaceState } from '../../../../../store/states/workspace.state'; +import { NO_ERRORS_SCHEMA } from '@angular/core'; +import { ArtifactsTabComponent } from './artifacts-tab.component'; +import { CompositionService } from '../../../composition.service'; +import { WorkspaceService } from '../../../../workspace/workspace.service'; +import { ComponentInstanceServiceNg2 } from '../../../../../services/component-instance-services/component-instance.service'; +import { TopologyTemplateService } from '../../../../../services/component-services/topology-template.service'; +import { ArtifactsService } from '../../../../../components/forms/artifacts-form/artifacts.service'; +import { ArtifactModel } from '../../../../../../models/artifacts'; +import { ArtifactType } from '../../../../../../utils/constants'; +import { FullComponentInstance } from '../../../../../../models/componentsInstances/fullComponentInstance'; +import { ComponentInstance } from '../../../../../../models/componentsInstances/componentInstance'; +import { Component } from '../../../../../../models/components/component'; +import { GetInstanceArtifactsByTypeAction } from '../../../../../store/actions/instance-artifacts.actions'; +import { Observable } from 'rxjs'; + + +describe('artifact-tab component', () => { + + let fixture: ComponentFixture; + let compositionMockService: Partial; + const workspaceMockService: Partial; + const componentInstanceMockService: Partial; + const topologyTemplateMockService: Partial; + let artifactsServiceMockService: Partial; + let store: Store; + + beforeEach( + async(() => { + compositionMockService = { + updateInstance: jest.fn() + } + + artifactsServiceMockService = { + deleteArtifact: jest.fn(), + openUpdateEnvParams: jest.fn(), + openArtifactModal: jest.fn() + } + + const configure: ConfigureFn = (testBed) => { + testBed.configureTestingModule({ + declarations: [ArtifactsTabComponent], + imports: [NgxsModule.forRoot([WorkspaceState])], + schemas: [NO_ERRORS_SCHEMA], + providers: [ + {provide: CompositionService, useValue: compositionMockService}, + {provide: WorkspaceService, useValue: workspaceMockService}, + {provide: ComponentInstanceServiceNg2, useValue: componentInstanceMockService}, + {provide: TopologyTemplateService, useValue: topologyTemplateMockService}, + {provide: ArtifactsService, useValue: artifactsServiceMockService} + ], + }); + }; + + configureTests(configure).then((testBed) => { + fixture = testBed.createComponent(ArtifactsTabComponent); + store = testBed.get(Store); + }); + }) + ); + + it ('on delete -> deleteArtifact is being called from artifactService', () => { + const artifact = new ArtifactModel(); + const topologyTemplateType: string = undefined; + const topologyTemplateId: string = undefined; + + fixture.componentInstance.delete(artifact); + expect(artifactsServiceMockService.deleteArtifact).toHaveBeenCalledWith(topologyTemplateType, topologyTemplateId, artifact); + }); + + it('should match current snapshot of artifact-tab component', () => { + expect(fixture).toMatchSnapshot(); + }); + + + it ('should get API Artifacts as Title', () => { + const artifactType = ArtifactType.SERVICE_API; + + const res = fixture.componentInstance.getTitle(artifactType); + expect(res).toBe('API Artifacts'); + }); + + + it ('should get Deployment Artifacts as Title', () => { + const artifactType = ArtifactType.DEPLOYMENT; + + const res = fixture.componentInstance.getTitle(artifactType); + expect(res).toBe('Deployment Artifacts'); + }); + + it ('should get Informational Artifacts as Title', () => { + const artifactType = ArtifactType.INFORMATION; + + const res = fixture.componentInstance.getTitle(artifactType); + expect(res).toBe('Informational Artifacts'); + }); + + it ('should get SomeString as Title - This is the default case (return the last val)', () => { + // So the last value will be "SomeString" + fixture.componentInstance.getTitle('SomeString'); + + const res = fixture.componentInstance.getTitle('SomeString'); + expect(res).toBe('SomeString Artifacts'); + }); + + + it ('should return isLicenseArtifact false', () => { + const artifact = new ArtifactModel(); + const componentInstance = new ComponentInstance(); + const component = new Component(); + fixture.componentInstance.component = new FullComponentInstance(componentInstance, component); + + let res = fixture.componentInstance.isLicenseArtifact(artifact); + expect(res).toBe(false); + }); + + it ('should return isLicenseArtifact true', () => { + const artifact = new ArtifactModel(); + const componentInstance = new ComponentInstance(); + const component = new Component(); + fixture.componentInstance.component = new FullComponentInstance(componentInstance, component); + fixture.componentInstance.component.isResource = jest.fn(() => true); + fixture.componentInstance.component.isCsarComponent = true; + + artifact.artifactType = ArtifactType.VENDOR_LICENSE; + const res = fixture.componentInstance.isLicenseArtifact(artifact); + expect(res).toBe(true); + }); + + it ('should verify getEnvArtifact with match', () => { + const artifact = new ArtifactModel(); + artifact.uniqueId = 'matchUniqueID'; + + const testItem1 = new ArtifactModel(); + testItem1.generatedFromId = 'matchUniqueID'; + + const testItem2 = new ArtifactModel(); + testItem2.generatedFromId = '123456'; + + const artifacts: ArtifactModel[] = [testItem1, testItem2]; + + const res = fixture.componentInstance.getEnvArtifact(artifact, artifacts); + expect(res.generatedFromId).toBe('matchUniqueID'); + }); + + it ('should verify getEnvArtifact with no match', () => { + const artifact = new ArtifactModel(); + artifact.uniqueId = 'matchUniqueID'; + + const testItem1 = new ArtifactModel(); + testItem1.generatedFromId = '654321'; + + const testItem2 = new ArtifactModel(); + testItem2.generatedFromId = '123456'; + + const artifacts: ArtifactModel[] = [testItem1, testItem2]; + + const res = fixture.componentInstance.getEnvArtifact(artifact, artifacts); + expect(res).toBe(undefined); + }); + + it ('on updateEnvParams -> openUpdateEnvParams is being called from artifactService when isComponentInstanceSelected = true', () => { + const artifact = new ArtifactModel(); + artifact.envArtifact = new ArtifactModel(); + + const topologyTemplateType: string = undefined; + const topologyTemplateId: string = undefined; + + const component = new Component(); + component.uniqueId = 'id'; + + const isComponentInstanceSelected = true; + + fixture.componentInstance.component = component; + fixture.componentInstance.isComponentInstanceSelected = isComponentInstanceSelected; + fixture.componentInstance.updateEnvParams(artifact); + + expect(artifactsServiceMockService.openUpdateEnvParams).toHaveBeenCalledWith(topologyTemplateType, topologyTemplateId, undefined, component.uniqueId); + }); + + it ('on updateEnvParams -> openUpdateEnvParams is being called from artifactService when isComponentInstanceSelected = false', () => { + const artifact = new ArtifactModel(); + + const topologyTemplateType: string = undefined + const topologyTemplateId: string = undefined; + + const component = new Component(); + + const isComponentInstanceSelected = false; + + fixture.componentInstance.component = component; + fixture.componentInstance.isComponentInstanceSelected = isComponentInstanceSelected; + fixture.componentInstance.updateEnvParams(artifact); + + expect(artifactsServiceMockService.openUpdateEnvParams).toHaveBeenCalledWith(topologyTemplateType, topologyTemplateId, artifact); + }); + + it ('on addOrUpdate -> openArtifactModal is being called from artifactService when isComponentInstanceSelected = true', () => { + const artifact = new ArtifactModel(); + + const topologyTemplateType: string = 'testType'; + const topologyTemplateId: string = 'testID'; + const type: string = 'testType'; + const isViewOnly: boolean = false; + + const component = new Component(); + component.uniqueId = 'id'; + + const isComponentInstanceSelected = true; + + fixture.componentInstance.component = component; + fixture.componentInstance.type = type; + fixture.componentInstance.topologyTemplateId = topologyTemplateId; + fixture.componentInstance.topologyTemplateType = topologyTemplateType; + fixture.componentInstance.isComponentInstanceSelected = isComponentInstanceSelected; + fixture.componentInstance.isViewOnly = isViewOnly; + fixture.componentInstance.addOrUpdate(artifact); + + + expect(artifactsServiceMockService.openArtifactModal).toHaveBeenCalledWith(topologyTemplateId, topologyTemplateType, artifact, type, isViewOnly, component.uniqueId); + }); + + it ('on addOrUpdate -> openArtifactModal is being called from artifactService when isComponentInstanceSelected = false', () => { + const artifact = new ArtifactModel(); + + const topologyTemplateType: string = 'testType'; + const topologyTemplateId: string = 'testID'; + const type: string = 'testType'; + const isViewOnly: boolean = false; + + const isComponentInstanceSelected = false; + + fixture.componentInstance.type = type; + fixture.componentInstance.isComponentInstanceSelected = isComponentInstanceSelected; + fixture.componentInstance.topologyTemplateId = topologyTemplateId; + fixture.componentInstance.topologyTemplateType = topologyTemplateType; + fixture.componentInstance.isViewOnly = isViewOnly; + fixture.componentInstance.addOrUpdate(artifact); + + expect(artifactsServiceMockService.openArtifactModal).toHaveBeenCalledWith(topologyTemplateId, topologyTemplateType, artifact, type, isViewOnly); + }); + + + it ('verify allowDeleteAndUpdateArtifact return false since isViewOnly=true', () => { + const artifact = new ArtifactModel(); + fixture.componentInstance.isViewOnly = true; + + const res = fixture.componentInstance.allowDeleteAndUpdateArtifact(artifact); + expect(res).toBe(false) + }); + + it ('verify allowDeleteAndUpdateArtifact return artifact.isFromCsar since isViewOnly=false && artifactGroupType = DEPLOYMENT', () => { + const artifact = new ArtifactModel(); + artifact.artifactGroupType = ArtifactType.DEPLOYMENT; + artifact.isFromCsar = false; + + fixture.componentInstance.isViewOnly = false; + + const res = fixture.componentInstance.allowDeleteAndUpdateArtifact(artifact); + expect(res).toBe(!artifact.isFromCsar); + }); + + it ('verify allowDeleteAndUpdateArtifact return !artifact.isHEAT() && !artifact.isThirdParty() &&' + + ' !this.isLicenseArtifact(artifact) since isViewOnly=false && artifactGroupType != DEPLOYMENT', () => { + const artifact = new ArtifactModel(); + artifact.artifactGroupType = 'NOT_DEPLOYMENT'; + artifact.isHEAT = () => false; + artifact.isThirdParty = () => false; + + fixture.componentInstance.isLicenseArtifact = jest.fn(() => false); + + fixture.componentInstance.isViewOnly = false; + + const res = fixture.componentInstance.allowDeleteAndUpdateArtifact(artifact); + expect(res).toBe(true ) + }); + + it('verify action on loadArtifacts in case isComponentInstanceSelected = true', () => { + fixture.componentInstance.isComponentInstanceSelected = true; + fixture.componentInstance.topologyTemplateType = 'topologyTemplateType'; + fixture.componentInstance.topologyTemplateId = 'topologyTemplateId'; + const component = new Component(); + component.uniqueId = 'uniqueId'; + fixture.componentInstance.component = component; + fixture.componentInstance.type = 'type'; + + const action = new GetInstanceArtifactsByTypeAction(({ + componentType: 'topologyTemplateType', + componentId: 'topologyTemplateId', + instanceId: 'uniqueId', + artifactType: 'type' + })) + + fixture.componentInstance.store.dispatch = jest.fn(() => Observable.of(true)); + fixture.componentInstance.loadArtifacts(); + + expect(store.dispatch).toBeCalledWith(action); + + }); +}); diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/artifacts-tab/artifacts-tab.component.html b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/artifacts-tab/artifacts-tab.component.html new file mode 100644 index 0000000000..264444b674 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/artifacts-tab/artifacts-tab.component.html @@ -0,0 +1,119 @@ +
+
+ +
{{title}}
+ +
+
+
+ +
+
{{artifact.artifactName}} +
+
+ + + + + + + + + + + + + + + + + + +
+
+ {{artifact.artifactDisplayName}} +
+ {{artifact.artifactDisplayName}} (ENV) +
+ + + +
+
+
+ +
+ Description:{{artifact.description}} +
+
+
+
+
+ +
+
+
+
diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/artifacts-tab/artifacts-tab.component.less b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/artifacts-tab/artifacts-tab.component.less new file mode 100644 index 0000000000..fef199dd97 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/artifacts-tab/artifacts-tab.component.less @@ -0,0 +1,169 @@ +@import '../../../../../../../assets/styles/override'; + + +.artifacts /deep/ .expand-collapse-content { + padding: 10px 0px; + + &.collapsed { + padding: 0 0; + } +} + +.i-sdc-designer-sidebar-section-content-item-artifact { + + &:not(:hover) .artifact-button { + display:none; + } + .artifact-buttons-container { + display: inline-flex; + flex-direction: row-reverse; + position: absolute; + right:0; + + &.upper-buttons { + margin-top: 8px; + } + + .artifact-button { + cursor:pointer; + padding-right:5px; + + &.edit-pencil { + margin-top: 10px; + } + } + } +} + +.w-sdc-designer-sidebar-section-footer { + padding: 20px; + display: flex; + justify-content: center; + +} + + +.w-sdc-designer-sidebar-tab-content.artifacts { + + .i-sdc-designer-sidebar-section-content-item-artifact.hand { + cursor: pointer; + } + + .w-sdc-designer-sidebar-section-content { + padding: 0; + } + .w-sdc-designer-sidebar-section-title { + &.expanded { + margin-bottom: 0; + } + } + + .i-sdc-designer-sidebar-section-content-item-artifact-details { + display: inline-block; + margin-left: 5px; + vertical-align: middle; + width: 180px; + &.heat { + line-height: 18px; + width: 250px; + } + } + + .i-sdc-designer-sidebar-section-content-item-artifact-details-name { + + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + max-width:220px; + display: inline-block; + //text-transform: capitalize; + &.enabled { + &:hover { + color: @sdcui_color_dark-blue; + } + } + + } + + .i-sdc-designer-sidebar-section-content-item-artifact-heat-env { + color: @sdcui_color_dark-gray; + margin-top: 6px; + line-height: 42px; + padding-top: 10px; + border-top:1px solid #c8cdd1; + .enabled { + &:hover { + cursor: pointer; + color: @sdcui_color_dark-blue; + } + } + } + + .i-sdc-designer-sidebar-section-content-item-artifact-filename { + color: @sdcui_color_dark-gray; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + max-width: 225px; + display: inline-block; + font-weight: bold; + &.enabled { + &:hover { + color: @sdcui_color_dark-blue; + } + } + } + + + .i-sdc-designer-sidebar-section-content-item-file-link{ + border-left: 1px #848586 solid; + height: 58px; + margin-left: -11px; + margin-top: 11px; + border-top: 1px #848586 solid; + border-bottom: 1px #848586 solid; + width: 12px; + float: left; + } + + .i-sdc-designer-sidebar-section-content-item-artifact-details-desc { + display: none; + line-height: 16px; + word-wrap: break-word; + white-space: normal; + } + + .i-sdc-designer-sidebar-section-content-item-artifact-details-desc-label { + color: @sdcui_color_dark-gray; + } + + + .i-sdc-designer-sidebar-section-content-item-artifact { + border-bottom: 1px solid #c8cdd1; + padding: 5px 10px 5px 18px; + position: relative; + // line-height: 36px; + min-height: 61px; + //cursor: default; + display: flex; + align-items: center; + + + .i-sdc-designer-sidebar-section-content-item-button { + top: 20px; + line-height: 10px; + } + + &:hover { + //background-color: @color_c; + background-color: white; + transition: all .3s; + + .i-sdc-designer-sidebar-section-content-item-button { + display: block; + + } + + } + } +} diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/artifacts-tab/artifacts-tab.component.ts b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/artifacts-tab/artifacts-tab.component.ts new file mode 100644 index 0000000000..53a6c267e2 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/artifacts-tab/artifacts-tab.component.ts @@ -0,0 +1,204 @@ +import { Component, Input } from '@angular/core'; +import { Store } from '@ngxs/store'; +import { ArtifactModel, Component as TopologyTemplate, FullComponentInstance, Resource } from 'app/models'; +import { WorkspaceService } from 'app/ng2/pages/workspace/workspace.service'; +import { ResourceNamePipe } from 'app/ng2/pipes/resource-name.pipe'; +import { ComponentInstanceServiceNg2 } from 'app/ng2/services/component-instance-services/component-instance.service'; +import { TopologyTemplateService } from 'app/ng2/services/component-services/topology-template.service'; +import { ArtifactType } from 'app/utils'; +import * as _ from 'lodash'; +import { SdcUiServices } from 'onap-ui-angular'; +import { Observable } from 'rxjs/Observable'; +import { map } from 'rxjs/operators'; +import { ArtifactsService } from '../../../../../components/forms/artifacts-form/artifacts.service'; +import { GetArtifactsByTypeAction } from '../../../../../store/actions/artifacts.action'; +import { GetInstanceArtifactsByTypeAction } from '../../../../../store/actions/instance-artifacts.actions'; +import { ArtifactsState } from '../../../../../store/states/artifacts.state'; +import { InstanceArtifactsState } from '../../../../../store/states/instance-artifacts.state'; +import { SelectedComponentType, TogglePanelLoadingAction } from '../../../common/store/graph.actions'; +import { CompositionService } from '../../../composition.service'; + +@Component({ + selector: 'artifacts-tab', + styleUrls: ['./artifacts-tab.component.less'], + templateUrl: './artifacts-tab.component.html', + providers: [SdcUiServices.ModalService] +}) + +export class ArtifactsTabComponent { + + @Input() component: FullComponentInstance | TopologyTemplate; + @Input() isViewOnly: boolean; + @Input() input: any; + @Input() componentType: SelectedComponentType; + + public title: string; + public type: string; + public isComponentInstanceSelected: boolean; + public artifacts$: Observable; + private topologyTemplateType: string; + private topologyTemplateId: string; + private heatToEnv: Map; + private resourceType: string; + private isComplex: boolean; + + constructor(private store: Store, + private compositionService: CompositionService, + private workspaceService: WorkspaceService, + private componentInstanceService: ComponentInstanceServiceNg2, + private topologyTemplateService: TopologyTemplateService, + private artifactService: ArtifactsService) { + this.heatToEnv = new Map(); + } + + ngOnInit() { + this.topologyTemplateType = this.workspaceService.metadata.componentType; + this.topologyTemplateId = this.workspaceService.metadata.uniqueId; + this.type = this.input.type; + this.title = this.getTitle(this.type); + this.isComponentInstanceSelected = this.componentType === SelectedComponentType.COMPONENT_INSTANCE; + this.resourceType = this.component['resourceType']; + this.isComplex = this.component.isComplex(); + this.loadArtifacts(); + } + + public addOrUpdate = (artifact: ArtifactModel): void => { + if (this.isComponentInstanceSelected) { + this.artifactService.openArtifactModal(this.topologyTemplateId, this.topologyTemplateType, artifact, this.type, this.isViewOnly, this.component.uniqueId); + } else { + this.artifactService.openArtifactModal(this.topologyTemplateId, this.topologyTemplateType, artifact, this.type, this.isViewOnly); + } + } + + public updateEnvParams = (artifact: ArtifactModel) => { + if (this.isComponentInstanceSelected) { + this.artifactService.openUpdateEnvParams(this.topologyTemplateType, this.topologyTemplateId, this.heatToEnv.get(artifact.uniqueId), this.component.uniqueId); + } else { + this.artifactService.openUpdateEnvParams(this.topologyTemplateType, this.topologyTemplateId, artifact); + } + } + + public viewEnvParams = (artifact: ArtifactModel) => { + if (this.isComponentInstanceSelected) { + this.artifactService.openViewEnvParams(this.topologyTemplateType, this.topologyTemplateId, this.heatToEnv.get(artifact.uniqueId), this.component.uniqueId); + } else { + this.artifactService.openViewEnvParams(this.topologyTemplateType, this.topologyTemplateId, artifact); + } + } + + public getEnvArtifact = (heatArtifact: ArtifactModel, artifacts: ArtifactModel[]): ArtifactModel => { + const envArtifact = _.find(artifacts, (item: ArtifactModel) => { + return item.generatedFromId === heatArtifact.uniqueId; + }); + if (envArtifact && heatArtifact) { + envArtifact.artifactDisplayName = heatArtifact.artifactDisplayName; + envArtifact.timeout = heatArtifact.timeout; + } + return envArtifact; + } + + public delete = (artifact: ArtifactModel): void => { + if (this.isComponentInstanceSelected) { + this.artifactService.deleteArtifact(this.topologyTemplateType, this.topologyTemplateId, artifact, this.component.uniqueId); + } else { + this.artifactService.deleteArtifact(this.topologyTemplateType, this.topologyTemplateId, artifact); + } + } + + public isVfOrPnf(): boolean { + if (this.component.isResource()){ + if (this.resourceType) { + return this.resourceType === 'VF' || this.resourceType == 'PNF'; + } + return false; + } + + return false; + } + + private envArtifactOf(artifact: ArtifactModel): ArtifactModel { + return this.heatToEnv.get(artifact.uniqueId); + } + + private isLicenseArtifact = (artifact: ArtifactModel): boolean => { + let isLicense: boolean = false; + if (this.component.isResource && (this.component as Resource).isCsarComponent) { + if (ArtifactType.VENDOR_LICENSE === artifact.artifactType || ArtifactType.VF_LICENSE === artifact.artifactType) { + isLicense = true; + } + } + + return isLicense; + } + + private getTitle = (artifactType: string): string => { + switch (artifactType) { + case ArtifactType.SERVICE_API: + return 'API Artifacts'; + case ArtifactType.DEPLOYMENT: + return 'Deployment Artifacts'; + case ArtifactType.INFORMATION: + return 'Informational Artifacts'; + default: + return ResourceNamePipe.getDisplayName(artifactType) + ' Artifacts'; + } + } + + private loadArtifacts = (forceLoad?: boolean): void => { + + this.store.dispatch(new TogglePanelLoadingAction({isLoading: true})); + + let action; + if (this.isComponentInstanceSelected) { + action = new GetInstanceArtifactsByTypeAction(({ + componentType: this.topologyTemplateType, + componentId: this.topologyTemplateId, + instanceId: this.component.uniqueId, + artifactType: this.type + })); + } else { + action = new GetArtifactsByTypeAction({ + componentType: this.topologyTemplateType, + componentId: this.topologyTemplateId, + artifactType: this.type + }); + } + this.store.dispatch(action).subscribe(() => { + const stateSelector = this.isComponentInstanceSelected ? InstanceArtifactsState.getArtifactsByType : ArtifactsState.getArtifactsByType; + this.artifacts$ = this.store.select(stateSelector).pipe(map((filterFn) => filterFn(this.type))).pipe(map((artifacts) => { + _.forEach(artifacts, (artifact: ArtifactModel): void => { + const envArtifact = this.getEnvArtifact(artifact, artifacts); // Extract the env artifact (if exist) of the HEAT artifact + if (envArtifact) { + // Set a mapping between HEAT to HEAT_ENV + this.heatToEnv.set(artifact.uniqueId, envArtifact); + } + }); + return _.orderBy(artifacts, ['mandatory', 'artifactDisplayName'], ['desc', 'asc']); + })); + + this.artifacts$.subscribe((artifacts) => { + _.forEach(artifacts, (artifact: ArtifactModel) => { + artifact.allowDeleteAndUpdate = this.allowDeleteAndUpdateArtifact(artifact); + }); + if (this.component instanceof FullComponentInstance) { + this.compositionService.updateInstance(this.component); + } + }); + this.store.dispatch(new TogglePanelLoadingAction({isLoading: false})); + }, () => { + this.store.dispatch(new TogglePanelLoadingAction({isLoading: false})); + }); + } + + private allowDeleteAndUpdateArtifact = (artifact: ArtifactModel): boolean => { + if (!this.isViewOnly) { + if (artifact.artifactGroupType === ArtifactType.DEPLOYMENT) { + return !artifact.isFromCsar; + } else { + + return (!artifact.isHEAT() && !artifact.isThirdParty() && !this.isLicenseArtifact(artifact)); + } + } + return false; + } +} diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/base/base-tab.component.less b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/base/base-tab.component.less deleted file mode 100644 index aa8e75115f..0000000000 --- a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/base/base-tab.component.less +++ /dev/null @@ -1,66 +0,0 @@ -@import './../../../../../../../assets/styles/mixins'; -@import "./../../../../../../../assets/styles/variables-old"; -@import './../../../../../../../assets/styles/mixins_old'; - -/deep/ -.expand-collapse-content { - padding: 20px; -} - -.component-details-panel-tab-no-data { - margin: 0 auto; - padding-top: 30px; - text-align: center; - - .component-details-panel-tab-no-data-title { - font-family: @font-opensans-bold; - } - -} - -.component-details-panel-large-item { - font-family: OpenSans-Semibold, sans-serif; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - height: 32px; - line-height: 32px; - vertical-align: middle; - - &:hover { - background-color: #f8f8f8; - margin: 0 -20px; /* to fill expand-collapse-content padding */ - padding: 0 20px; - .component-details-panel-item-delete { - visibility: visible; - } - } -} - -.component-details-panel-item { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - height: 22px; - line-height: 22px; - vertical-align: middle; - - &.description { - margin-top: 28px; - white-space: normal; - word-wrap: break-word; - .value { - max-width: none; - font-weight: normal; - font-family: @font-opensans-regular; - } - } - - .name { font-family: OpenSans-Semibold, sans-serif; } - .value { } -} - -.component-details-panel-item-delete { - cursor: pointer; - visibility: hidden; -} diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/group-members-tab/group-members-tab.component.html b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/group-members-tab/group-members-tab.component.html new file mode 100644 index 0000000000..8c5c9c7663 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/group-members-tab/group-members-tab.component.html @@ -0,0 +1,47 @@ + + +

Members + + +

+
+
    +
  • + {{member.name}} + +
  • +
+ +
+
No data to display yet
+
Add members to group to see members
+
+
diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/group-members-tab/group-members-tab.component.spec.ts b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/group-members-tab/group-members-tab.component.spec.ts new file mode 100644 index 0000000000..43f6aac2c7 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/group-members-tab/group-members-tab.component.spec.ts @@ -0,0 +1,127 @@ +import { NO_ERRORS_SCHEMA } from '@angular/core'; +import { async, ComponentFixture } from '@angular/core/testing'; +import { SdcUiCommon, SdcUiComponents, SdcUiServices } from 'onap-ui-angular'; +import { Observable } from 'rxjs/Rx'; +import { Mock } from 'ts-mockery'; +import { ConfigureFn, configureTests } from '../../../../../../../jest/test-config.helper'; +import { ComponentMetadata } from '../../../../../../models/component-metadata'; +import { GroupInstance } from '../../../../../../models/graph/zones/group-instance'; +import { EventListenerService } from '../../../../../../services/event-listener-service'; +import { GroupsService } from '../../../../../services/groups.service'; +import { TranslateService } from '../../../../../shared/translator/translate.service'; +import { WorkspaceService } from '../../../../workspace/workspace.service'; +import { CompositionService } from '../../../composition.service'; +import { GroupMembersTabComponent } from './group-members-tab.component'; + +describe('group members tab component', () => { + + let fixture: ComponentFixture; + + // Mocks + let workspaceServiceMock: Partial; + let eventsListenerServiceMock: Partial; + let groupServiceMock: Partial; + let loaderServiceMock: Partial; + let compositionServiceMock: Partial; + let modalServiceMock: Partial; + + const membersToAdd = [ + {uniqueId: '1', name: 'inst1'}, + {uniqueId: '2', name: 'inst2'}, + ]; + + beforeEach( + async(() => { + + eventsListenerServiceMock = {}; + + groupServiceMock = Mock.of( + { + updateMembers: jest.fn().mockImplementation((compType, uid, groupUniqueId, updatedMembers) => { + if (updatedMembers === undefined) { + return Observable.throwError('error'); + } else { + return Observable.of(updatedMembers); + } + } + )}); + + compositionServiceMock = { + getComponentInstances: jest.fn().mockImplementation( () => { + return [{uniqueId: '1', name: 'inst1'}, + {uniqueId: '2', name: 'inst2'}, + {uniqueId: '3', name: 'inst3'}, + {uniqueId: '4', name: 'inst4'}, + {uniqueId: '5', name: 'inst5'} + ]; + } + ) + }; + + workspaceServiceMock = { + metadata: Mock.of() + }; + + const addMemberModalInstance = { + innerModalContent: { instance: { existingElements: membersToAdd }}, + closeModal: jest.fn() + }; + + modalServiceMock = { + openInfoModal: jest.fn(), + openCustomModal: jest.fn().mockImplementation(() => addMemberModalInstance) + }; + + loaderServiceMock = { + activate: jest.fn(), + deactivate: jest.fn() + }; + + const groupInstanceMock = Mock.of(); + + const configure: ConfigureFn = (testBed) => { + testBed.configureTestingModule({ + declarations: [GroupMembersTabComponent], + schemas: [NO_ERRORS_SCHEMA], + providers: [ + {provide: TranslateService, useValue: { translate: jest.fn() }}, + {provide: GroupsService, useValue: groupServiceMock}, + {provide: SdcUiServices.ModalService, useValue: modalServiceMock }, + {provide: EventListenerService, useValue: eventsListenerServiceMock }, + {provide: CompositionService, useValue: compositionServiceMock }, + {provide: WorkspaceService, useValue: workspaceServiceMock}, + {provide: SdcUiServices.LoaderService, useValue: loaderServiceMock } + ], + }); + }; + + configureTests(configure).then((testBed) => { + fixture = testBed.createComponent(GroupMembersTabComponent); + fixture.componentInstance.group = groupInstanceMock; + }); + }) + ); + + it('test that initially all members are available for adding', () => { + const testedComponent = fixture.componentInstance; + + // No members are currently in the group, all 5 members should be returned + const optionalMembersToAdd = testedComponent.getOptionalsMembersToAdd(); + expect(optionalMembersToAdd).toHaveLength(5); + }); + + it('test list of available instances to add does not include existing members', () => { + const testedComponent = fixture.componentInstance; + + // Mock the group instance to return the members that we are about to add + testedComponent.group.getMembersAsUiObject = jest.fn().mockImplementation( () => membersToAdd); + + // The opened modal shall return 2 members to be added + testedComponent.openAddMembersModal(); + testedComponent.addMembers(); // Shall add 2 members (1,2) + + // Now the getOptionalsMembersToAdd shall return 3 which are the members that were no added yet + const optionalMembersToAdd = testedComponent.getOptionalsMembersToAdd(); + expect(optionalMembersToAdd).toHaveLength(3); + }); +}); diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/group-members-tab/group-members-tab.component.ts b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/group-members-tab/group-members-tab.component.ts new file mode 100644 index 0000000000..7f1222367d --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/group-members-tab/group-members-tab.component.ts @@ -0,0 +1,158 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 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. + * ============LICENSE_END========================================================= + */ + +import { Component, HostBinding, Input, OnDestroy, OnInit } from '@angular/core'; +import { Select } from '@ngxs/store'; +import { GroupInstance } from 'app/models/graph/zones/group-instance'; +import { CompositionService } from 'app/ng2/pages/composition/composition.service'; +import { WorkspaceService } from 'app/ng2/pages/workspace/workspace.service'; +import { EventListenerService } from 'app/services/event-listener-service'; +import { GRAPH_EVENTS } from 'app/utils'; +import * as _ from 'lodash'; +import { SdcUiCommon, SdcUiComponents, SdcUiServices } from 'onap-ui-angular'; +import { Observable, Subscription } from 'rxjs'; +import { tap } from 'rxjs/operators'; +import { ComponentInstance } from '../../../../../../models/componentsInstances/componentInstance'; +import { MemberUiObject } from '../../../../../../models/ui-models/ui-member-object'; +import { AddElementsComponent } from '../../../../../components/ui/modal/add-elements/add-elements.component'; +import {GraphState} from "../../../common/store/graph.state"; +import { GroupsService } from '../../../../../services/groups.service'; +import { TranslateService } from '../../../../../shared/translator/translate.service'; + +@Component({ + selector: 'group-members-tab', + templateUrl: './group-members-tab.component.html', + styleUrls: ['./../policy-targets-tab/policy-targets-tab.component.less'] +}) + +export class GroupMembersTabComponent implements OnInit, OnDestroy { + + @Input() group: GroupInstance; + @Input() isViewOnly: boolean; + @Select(GraphState.getSelectedComponent) group$: Observable; + @HostBinding('class') classes = 'component-details-panel-tab-group-members'; + + private members: MemberUiObject[]; + private addMemberModalInstance: SdcUiComponents.ModalComponent; + private subscription: Subscription; + + constructor( + private translateService: TranslateService, + private groupsService: GroupsService, + private modalService: SdcUiServices.ModalService, + private eventListenerService: EventListenerService, + private compositionService: CompositionService, + private workspaceService: WorkspaceService, + private loaderService: SdcUiServices.LoaderService + ) { + } + + ngOnInit() { + this.subscription = this.group$.pipe( + tap((group) => { + this.group = group; + this.members = this.group.getMembersAsUiObject(this.compositionService.componentInstances); + })).subscribe(); + } + + ngOnDestroy() { + if (this.subscription) { + this.subscription.unsubscribe(); + } + } + + deleteMember = (member: MemberUiObject): void => { + this.loaderService.activate(); + this.groupsService.deleteGroupMember( + this.workspaceService.metadata.componentType, + this.workspaceService.metadata.uniqueId, + this.group, + member.uniqueId).subscribe( + (updatedMembers: string[]) => { + this.group.members = updatedMembers; + this.initMembers(); + this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_GROUP_INSTANCE_UPDATE, this.group); + }, + () => console.log('Error deleting member!'), + () => this.loaderService.deactivate() + ); + } + + addMembers = (): void => { + // TODO refactor sdc-ui modal in order to return the data + const membersToAdd: MemberUiObject[] = this.addMemberModalInstance.innerModalContent.instance.existingElements; + if (membersToAdd.length > 0) { + this.addMemberModalInstance.closeModal(); + this.loaderService.activate(); + const locallyUpdatedMembers: MemberUiObject[] = _.union(this.members, membersToAdd); + this.groupsService.updateMembers( + this.workspaceService.metadata.componentType, + this.workspaceService.metadata.uniqueId, + this.group.uniqueId, + locallyUpdatedMembers).subscribe( + (updatedMembers: string[]) => { + this.group.members = updatedMembers; + this.initMembers(); + this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_GROUP_INSTANCE_UPDATE, this.group); + }, + () => { + console.log('Error updating members!'); + }, () => + this.loaderService.deactivate() + ); + } + } + + getOptionalsMembersToAdd(): MemberUiObject[] { + const optionalsMembersToAdd: MemberUiObject[] = []; + // adding all instances as optional members to add if not already exist + _.forEach(this.compositionService.getComponentInstances(), (instance: ComponentInstance) => { + if (!_.some(this.members, (member: MemberUiObject) => { + return member.uniqueId === instance.uniqueId; + })) { + optionalsMembersToAdd.push(new MemberUiObject(instance.uniqueId, instance.name)); + } + }); + return optionalsMembersToAdd; + } + + openAddMembersModal(): void { + const addMembersModalConfig = { + title: this.group.name + ' ADD MEMBERS', + size: 'md', + type: SdcUiCommon.ModalType.custom, + testId: 'addMembersModal', + buttons: [ + {text: 'ADD MEMBERS', size: 'medium', callback: this.addMembers, closeModal: false}, + {text: 'CANCEL', size: 'sm', type: 'secondary', closeModal: true} + ] + } as SdcUiCommon.IModalConfig; + const optionalsMembersToAdd = this.getOptionalsMembersToAdd(); + this.addMemberModalInstance = this.modalService.openCustomModal(addMembersModalConfig, AddElementsComponent, { + elementsToAdd: optionalsMembersToAdd, + elementName: 'member' + }); + } + + private initMembers = (groupInstance?: GroupInstance) => { + this.group = groupInstance ? groupInstance : this.group; + this.members = this.group.getMembersAsUiObject(this.compositionService.getComponentInstances()); + } +} diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/group-or-policy-properties-tab/group-or-policy-properties-tab.component.html b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/group-or-policy-properties-tab/group-or-policy-properties-tab.component.html new file mode 100644 index 0000000000..c57f99786c --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/group-or-policy-properties-tab/group-or-policy-properties-tab.component.html @@ -0,0 +1,39 @@ + + + +
Properties
+ +
    +
  • +
    {{property.name}} +
    +
    {{property.value || property.defaultValue}} +
    +
  • +
+ +
+
No properties to display
+
+
+
diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/group-or-policy-properties-tab/group-or-policy-properties-tab.component.ts b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/group-or-policy-properties-tab/group-or-policy-properties-tab.component.ts new file mode 100644 index 0000000000..24ae8b2833 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/group-or-policy-properties-tab/group-or-policy-properties-tab.component.ts @@ -0,0 +1,52 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 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. + * ============LICENSE_END========================================================= + */ + +import * as _ from "lodash"; +import { Component, Inject, Input} from "@angular/core"; +import { TranslateService } from './../../../../../shared/translator/translate.service'; +import { PolicyInstance } from 'app/models/graph/zones/policy-instance'; +import { PropertyModel } from './../../../../../../models/properties'; +import { ModalsHandler } from "app/utils"; +import { Component as TopologyTemplate, GroupInstance } from "app/models"; + +@Component({ + selector: 'group-or-policy-properties-tab', + templateUrl: './group-or-policy-properties-tab.component.html', + styleUrls: ['./../properties-tab/properties-tab.component.less'], +}) +export class GroupOrPolicyPropertiesTab { + + @Input() component: GroupInstance | PolicyInstance; + @Input() topologyTemplate:TopologyTemplate; + @Input() isViewOnly: boolean; + @Input() input: {type: string}; + + + constructor(private translateService:TranslateService, private ModalsHandler:ModalsHandler) { + } + + + editProperty = (property?:PropertyModel):void => { + this.ModalsHandler.openEditPropertyModal((property ? property : new PropertyModel()), this.topologyTemplate, this.component.properties, false, this.input.type, this.component.uniqueId).then((updatedProperty:PropertyModel) => { + console.log("ok"); + }); + } + +} diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-information-tab.component.html b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-information-tab.component.html deleted file mode 100644 index 953b57bda1..0000000000 --- a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-information-tab.component.html +++ /dev/null @@ -1,47 +0,0 @@ - - - - - -
General Info
- - - -
- - Group -
- - -
- - Group -
- - -
- - {{group.version}} -
- - -
- - {{group.description}} -
-
-
diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-information-tab.component.ts b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-information-tab.component.ts deleted file mode 100644 index 26602224da..0000000000 --- a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-information-tab.component.ts +++ /dev/null @@ -1,39 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * SDC - * ================================================================================ - * Copyright (C) 2017 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. - * ============LICENSE_END========================================================= - */ - -import * as _ from "lodash"; -import { Component, Inject, Input, Output, EventEmitter } from "@angular/core"; -import { GroupInstance } from 'app/models/graph/zones/group-instance'; - -@Component({ - selector: 'group-information-tab', - templateUrl: './group-information-tab.component.html', - styleUrls: ['./../base/base-tab.component.less'] -}) -export class GroupInformationTabComponent { - - @Input() group: GroupInstance; - @Input() isViewOnly: boolean; - - constructor() { - - } - -} diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-members-tab.component.html b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-members-tab.component.html deleted file mode 100644 index 6585ad2da9..0000000000 --- a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-members-tab.component.html +++ /dev/null @@ -1,47 +0,0 @@ - - -
Members - - -
-
-
    -
  • - {{member.name}} - -
  • -
- -
-
No data to display yet
-
Add members to group to see members
-
-
diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-members-tab.component.less b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-members-tab.component.less deleted file mode 100644 index 1006e864fa..0000000000 --- a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-members-tab.component.less +++ /dev/null @@ -1,13 +0,0 @@ -/deep/ -.component-details-panel-tab-group-members { - .component-details-panel-large-item { - display: flex; - flex-direction: row; - justify-content: space-between; - } - - .w-sdc-designer-sidebar-section-title { - display: flex; - justify-content: space-between; - } -} \ No newline at end of file diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-members-tab.component.ts b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-members-tab.component.ts deleted file mode 100644 index 148f2133e8..0000000000 --- a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-members-tab.component.ts +++ /dev/null @@ -1,133 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * SDC - * ================================================================================ - * Copyright (C) 2017 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. - * ============LICENSE_END========================================================= - */ - -import * as _ from "lodash"; -import { Component, Input, Output, EventEmitter, OnChanges, HostBinding } from "@angular/core"; -import { TranslateService } from './../../../../../shared/translator/translate.service'; -import { Component as TopologyTemplate } from "app/models"; -import { GroupInstance } from "app/models/graph/zones/group-instance"; -import { GroupsService } from "../../../../../services/groups.service"; -import { SimpleChanges } from "@angular/core/src/metadata/lifecycle_hooks"; -import { MemberUiObject } from "../../../../../../models/ui-models/ui-member-object"; -import { IModalConfig } from "sdc-ui/lib/angular/modals/models/modal-config"; -import { AddElementsComponent } from "../../../../../components/ui/modal/add-elements/add-elements.component"; -import { GRAPH_EVENTS } from 'app/utils'; -import { EventListenerService } from 'app/services/event-listener-service'; -import { ComponentInstance } from "../../../../../../models/componentsInstances/componentInstance"; -import { SdcUiComponents } from "sdc-ui/lib/angular"; - -@Component({ - selector: 'group-members-tab', - templateUrl: './group-members-tab.component.html', - styleUrls: ['./../base/base-tab.component.less', 'group-members-tab.component.less'] -}) - -export class GroupMembersTabComponent implements OnChanges { - - - private members: Array; - - @Input() group: GroupInstance; - @Input() topologyTemplate: TopologyTemplate; - @Input() isViewOnly: boolean; - @Output() isLoading: EventEmitter = new EventEmitter(); - @HostBinding('class') classes = 'component-details-panel-tab-group-members'; - - constructor(private translateService: TranslateService, - private groupsService: GroupsService, - private modalService: SdcUiComponents.ModalService, - private eventListenerService: EventListenerService - ) { - this.eventListenerService.registerObserverCallback(GRAPH_EVENTS.ON_GROUP_INSTANCE_UPDATE, this.initMembers) - } - - ngOnChanges(changes:SimpleChanges):void { - this.initMembers(); - } - - deleteMember = (member: MemberUiObject):void => { - this.isLoading.emit(true); - this.groupsService.deleteGroupMember(this.topologyTemplate.componentType, this.topologyTemplate.uniqueId, this.group, member.uniqueId).subscribe( - (updatedMembers:Array) => { - this.group.members = updatedMembers; - this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_GROUP_INSTANCE_UPDATE, this.group); - }, - error => console.log("Error deleting member!"), - () => this.isLoading.emit(false) - ); - } - - private initMembers = (groupInstance?: GroupInstance) => { - this.group = groupInstance ? groupInstance : this.group; - this.members = this.group.getMembersAsUiObject(this.topologyTemplate.componentInstances); - } - - addMembers = ():void => { - var membersToAdd:Array = this.modalService.getCurrentInstance().innerModalContent.instance.existingElements; //TODO refactor sdc-ui modal in order to return the data - if(membersToAdd.length > 0) { - this.modalService.closeModal(); - this.isLoading.emit(true); - var updatedMembers: Array = _.union(this.members, membersToAdd); - this.groupsService.updateMembers(this.topologyTemplate.componentType, this.topologyTemplate.uniqueId, this.group.uniqueId, updatedMembers).subscribe( - (updatedMembers:Array) => { - this.group.members = updatedMembers; - this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_GROUP_INSTANCE_UPDATE, this.group); - }, - error => { - console.log("Error updating members!"); - }, () => - this.isLoading.emit(false) - ); - } - } - - getOptionalsMembersToAdd():Array { - - let optionalsMembersToAdd:Array = []; - - // adding all instances as optional members to add if not already exist - _.forEach(this.topologyTemplate.componentInstances, (instance:ComponentInstance) => { - if (!_.some(this.members, (member:MemberUiObject) => { - return member.uniqueId === instance.uniqueId - })) { - optionalsMembersToAdd.push(new MemberUiObject(instance.uniqueId, instance.name)); - } - }); - return optionalsMembersToAdd; - } - - openAddMembersModal():void { - let addMembersModalConfig:IModalConfig = { - title: this.group.name + " ADD MEMBERS", - size: "md", - type: "custom", - testId: "addMembersModal", - buttons: [ - {text: 'ADD MEMBERS', size: 'xsm', callback: this.addMembers, closeModal: false}, - {text: 'CANCEL', size: 'sm', type: "secondary", closeModal: true} - ] - }; - var optionalsMembersToAdd = this.getOptionalsMembersToAdd(); - this.modalService.openCustomModal(addMembersModalConfig, AddElementsComponent, { - elementsToAdd: optionalsMembersToAdd, - elementName: "member" - }); - } -} diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-properties-tab.component.html b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-properties-tab.component.html deleted file mode 100644 index fe1f6b4f0d..0000000000 --- a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-properties-tab.component.html +++ /dev/null @@ -1,39 +0,0 @@ - - - -
Properties
- -
    -
  • -
    {{property.name}} -
    -
    {{property.value || property.defaultValue}} -
    -
  • -
- -
-
No properties to display
-
-
-
diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-properties-tab.component.less b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-properties-tab.component.less deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-properties-tab.component.ts b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-properties-tab.component.ts deleted file mode 100644 index 69079347c4..0000000000 --- a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-properties-tab.component.ts +++ /dev/null @@ -1,64 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * SDC - * ================================================================================ - * Copyright (C) 2017 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. - * ============LICENSE_END========================================================= - */ - -import * as _ from "lodash"; -import { Component, Inject, Input, Output, EventEmitter, OnChanges, SimpleChanges } from "@angular/core"; -import { TranslateService } from './../../../../../shared/translator/translate.service'; -import { GroupInstance } from 'app/models/graph/zones/group-instance'; -import { PropertyBEModel } from 'app/models'; -import { PropertyModel } from './../../../../../../models/properties'; -import { ModalsHandler } from "app/utils"; -import { Component as TopologyTemplate, ComponentInstance, IAppMenu } from "app/models"; - -@Component({ - selector: 'group-properties-tab', - templateUrl: './group-properties-tab.component.html', - styleUrls: ['./../base/base-tab.component.less', 'group-properties-tab.component.less'], - host: {'class': 'component-details-panel-tab-group-properties'} -}) -export class GroupPropertiesTabComponent implements OnChanges { - - @Input() group:GroupInstance; - @Input() topologyTemplate:TopologyTemplate; - @Input() isViewOnly: boolean; - - private properties:Array; - - constructor(private translateService:TranslateService, private ModalsHandler:ModalsHandler) { - } - - ngOnChanges(changes: SimpleChanges): void { - console.log("GroupPropertiesTabComponent: ngAfterViewInit: "); - console.log("group: " + JSON.stringify(this.group)); - this.properties = []; - this.initProperties(); - } - - initProperties = ():void => { - this.properties= this.group.properties; - } - - editProperty = (property?:PropertyModel):void => { - this.ModalsHandler.openEditPropertyModal((property ? property : new PropertyModel()), this.topologyTemplate, this.properties, false, 'group', this.group.uniqueId).then((updatedProperty:PropertyModel) => { - console.log("ok"); - }); - } - -} diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-tabs.component.html b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-tabs.component.html deleted file mode 100644 index 482de5eacf..0000000000 --- a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-tabs.component.html +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - - - - diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-tabs.component.ts b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-tabs.component.ts deleted file mode 100644 index 975d5c6153..0000000000 --- a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-tabs.component.ts +++ /dev/null @@ -1,67 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * SDC - * ================================================================================ - * Copyright (C) 2017 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. - * ============LICENSE_END========================================================= - */ - -import * as _ from "lodash"; -import { Component, Inject, Input, Output, EventEmitter, SimpleChanges, OnChanges } from "@angular/core"; -import { TranslateService } from './../../../../../shared/translator/translate.service'; -import { Component as TopologyTemplate, ComponentInstance, IAppMenu } from "app/models"; -import { GroupsService } from '../../../../../services/groups.service'; -import { GroupInstance } from "app/models/graph/zones/group-instance"; - -@Component({ - selector: 'group-tabs', - templateUrl: './group-tabs.component.html' -}) -export class GroupTabsComponent implements OnChanges { - - @Input() topologyTemplate:TopologyTemplate; - @Input() selectedZoneInstanceType:string; - @Input() selectedZoneInstanceId:string; - @Input() isViewOnly: boolean; - @Output() isLoading: EventEmitter = new EventEmitter(); - - private group:GroupInstance; - - constructor(private translateService:TranslateService, - private groupsService:GroupsService - ) { - } - - ngOnChanges(changes: SimpleChanges): void { - this.initGroup(); - } - - private initGroup = ():void => { - this.isLoading.emit(true); - this.groupsService.getSpecificGroup(this.topologyTemplate.componentType, this.topologyTemplate.uniqueId, this.selectedZoneInstanceId).subscribe( - group => { - this.group = group; - console.log(JSON.stringify(group)); - }, - error => console.log("Error getting group!"), - () => this.isLoading.emit(false) - ); - } - - private setIsLoading = (value) :void => { - this.isLoading.emit(value); - } - -} diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-tabs.module.ts b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-tabs.module.ts deleted file mode 100644 index 50797f862c..0000000000 --- a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-tabs.module.ts +++ /dev/null @@ -1,71 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * SDC - * ================================================================================ - * Copyright (C) 2017 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. - * ============LICENSE_END========================================================= - */ -import { NgModule } from "@angular/core"; -import { HttpModule } from "@angular/http"; -import { FormsModule } from "@angular/forms"; -import { BrowserModule } from "@angular/platform-browser"; -import { UiElementsModule } from 'app/ng2/components/ui/ui-elements.module'; -import { ExpandCollapseComponent } from 'app/ng2/components/ui/expand-collapse/expand-collapse.component'; -import { PoliciesService } from "../../../../../services/policies.service"; -import { GroupInformationTabComponent } from './group-information-tab.component'; -import { TooltipModule } from './../../../../../components/ui/tooltip/tooltip.module'; -import { GroupTabsComponent } from "./group-tabs.component"; -import { SdcUiComponentsModule } from "sdc-ui/lib/angular"; -import { GroupMembersTabComponent } from './group-members-tab.component'; -import { TranslateModule } from './../../../../../shared/translator/translate.module'; -import { GroupPropertiesTabComponent } from "./group-properties-tab.component"; - -@NgModule({ - declarations: [ - GroupInformationTabComponent, - GroupMembersTabComponent, - GroupTabsComponent, - GroupPropertiesTabComponent - ], - imports: [ - BrowserModule, - FormsModule, - HttpModule, - TooltipModule, - UiElementsModule, - SdcUiComponentsModule, - TranslateModule - ], - entryComponents: [ - GroupInformationTabComponent, - GroupMembersTabComponent, - GroupTabsComponent, - GroupPropertiesTabComponent, - ExpandCollapseComponent - ], - exports: [ - TooltipModule, - GroupInformationTabComponent, - GroupMembersTabComponent, - GroupTabsComponent, - GroupPropertiesTabComponent - ], - providers: [ - PoliciesService - ] -}) -export class GroupTabsModule { - -} diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/info-tab/__snapshots__/info-tab.component.spec.ts.snap b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/info-tab/__snapshots__/info-tab.component.spec.ts.snap new file mode 100644 index 0000000000..fdd0dcf75c --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/info-tab/__snapshots__/info-tab.component.spec.ts.snap @@ -0,0 +1,66 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`InfoTabComponent can load instance 1`] = ` + + +
+ General Info +
+ + + +
+ + + +
+ + + + + + + + + + + +
+ + +
+ + +
+
+
+`; diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/info-tab/info-tab.component.html b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/info-tab/info-tab.component.html new file mode 100644 index 0000000000..71545f8143 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/info-tab/info-tab.component.html @@ -0,0 +1,174 @@ + + + +
General Info
+ + +
+ + {{component.componentType}} +
+ + +
+ + {{component.resourceType}} +
+ + +
+ + {{component.version}} + + + +
+ + + +
+ + {{component.categories[0].name}} +
+ + +
+ + {{component.categories[0].subcategories[0].name}} +
+
+ + +
+ + {{component.creationDate | date: 'MM/dd/yyyy'}} +
+ + +
+ + {{component.creatorFullName}} +
+ + +
+ + {{component.vendorName}} +
+ + +
+ + {{component.vendorRelease}} +
+ + +
+ + {{component.resourceVendorModelNumber}} +
+ + +
+ + {{component.serviceType}} +
+ + +
+ + {{component.serviceRole}} +
+ + +
+ + {{component.contactId}} +
+ + +
+ + {{component.sourceModelName}} +
+ + +
+ + {{component.customizationUUID}} +
+ + +
+ + +
+ + + + + +
+ + {{component.policyTypeUid}} +
+ + +
+ + Policy +
+ + +
+ + Policy +
+
+ + + + +
+ + Group +
+ + +
+ + Group +
+ +
+ +
+
+ + +
Tags
+ + {{component.name}} + {{tag}} + +
diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/info-tab/info-tab.component.less b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/info-tab/info-tab.component.less new file mode 100644 index 0000000000..c8da4e3e68 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/info-tab/info-tab.component.less @@ -0,0 +1,51 @@ +@import '../../../../../../../assets/styles/variables'; + +.general-info-container { + display: flex; + flex-direction: column; + padding: 10px 20px; +} + +.component-details-panel-item { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + margin-bottom: 5px; + order:1; + + .name { font-family: OpenSans-Semibold, sans-serif; } + .value { padding-left: 10px; } + + + &.description { + margin-top: 28px; + white-space: normal; + word-wrap: break-word; + overflow: ellipsis; + + .value { + padding-left: 0; + max-width: none; + font-weight: normal; + font-family: @font-opensans-regular; + } + } + + &.group-item, &.policy-item { + order:0; + } +} + +.tags-container { + display: flex; + flex-wrap: wrap; + padding: 10px 20px; + + .i-sdc-designer-sidebar-section-content-item-tag { + padding: 5px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + user-select: all; + } +} diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/info-tab/info-tab.component.spec.ts b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/info-tab/info-tab.component.spec.ts new file mode 100644 index 0000000000..6915d651f1 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/info-tab/info-tab.component.spec.ts @@ -0,0 +1,98 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { NO_ERRORS_SCHEMA } from '@angular/core'; +import { Store } from '@ngxs/store'; +import { CompositionPaletteService } from '../../../../../pages/composition/palette/services/palette.service'; +import { IAppMenu, SdcMenuToken } from '../../../../../../../app/ng2/config/sdc-menu.config'; +import { CompositionService } from '../../../../../pages/composition/composition.service'; +import { ServiceServiceNg2 } from '../../../../../../../app/services-ng2'; +import { WorkspaceService } from '../../../../../../../app/ng2/pages/workspace/workspace.service'; +import { ComponentInstanceServiceNg2 } from '../../../../../../../app/ng2/services/component-instance-services/component-instance.service'; +import { EventListenerService } from '../../../../../../../app/services'; +import { InfoTabComponent } from './info-tab.component'; +import { ConfigureFn, configureTests } from "../../../../../../../jest/test-config.helper"; +import { Observable } from "rxjs"; +import { leftPaletteElements } from "../../../../../../../jest/mocks/left-paeltte-elements.mock"; +import { TranslatePipe } from "../../../../../shared/translator/translate.pipe"; +import { HttpClientModule } from "@angular/common/http"; +import { TranslateModule } from "../../../../../../../app/ng2/shared/translator/translate.module"; +import _ from "lodash"; +import { TranslateService } from "../../../../../shared/translator/translate.service"; +import { SdcUiServices } from "onap-ui-angular"; +import { Component as TopologyTemplate, FullComponentInstance, ComponentInstance } from '../../../../../../../app/models'; + + +describe('InfoTabComponent', () => { + // let comp: InfoTabComponent; + let fixture: ComponentFixture; + + // let eventServiceMock: Partial; + let storeStub:Partial; + let compositionPaletteServiceStub:Partial; + let iAppMenuStub:Partial; + let compositionServiceStub:Partial; + let serviceServiceNg2Stub:Partial; + let workspaceServiceStub:Partial; + let componentInstanceServiceNg2Stub:Partial; + let eventListenerServiceStub:Partial; + + beforeEach( + async(() => { + storeStub = {}; + iAppMenuStub = {}; + eventListenerServiceStub = { + notifyObservers: jest.fn() + } + compositionPaletteServiceStub = { + getLeftPaletteElements: jest.fn().mockImplementation(()=> Observable.of(leftPaletteElements)) + } + const configure: ConfigureFn = testBed => { + testBed.configureTestingModule({ + imports: [ ], + declarations: [ InfoTabComponent, TranslatePipe ], + schemas: [ NO_ERRORS_SCHEMA ], + providers: [ + { provide: Store, useValue: {} }, + { provide: CompositionPaletteService, useValue: compositionPaletteServiceStub }, + { provide: SdcMenuToken, useValue: {} }, + { provide: CompositionService, useValue: {} }, + { provide: SdcUiServices.ModalService, useValue: {}}, + { provide: ServiceServiceNg2, useValue: {} }, + { provide: WorkspaceService, useValue: {} }, + { provide: ComponentInstanceServiceNg2, useValue: {} }, + { provide: EventListenerService, useValue: eventListenerServiceStub }, + { provide: TranslateService, useValue: {}} + ] + }); + }; + + configureTests(configure).then(testBed => { + fixture = testBed.createComponent(InfoTabComponent); + let comp = fixture.componentInstance; + + }); + }) + ); + + + it('can load instance', () => { + expect(fixture).toMatchSnapshot(); + }); + + describe('Version dropdown', () => { + it('is undefined for topologyTemplate', () => { + fixture.componentInstance.component = {}; + fixture.componentInstance.initEditResourceVersion(fixture.componentInstance.component, fixture.componentInstance.flatLeftPaletteElementsFromService(leftPaletteElements)); + expect(fixture.componentInstance.versions).toBe(undefined); + }); + it('does not contain the highest minor version if it is checked out', () => { + fixture.componentInstance.component = new ComponentInstance(); + fixture.componentInstance.component.allVersions = + {'1.0': "9c829122-af05-4bc9-b537-5d84f4c8ae25", '1.1': "930d56cb-868d-4e35-bd0f-e737d2fdb171"}; + fixture.componentInstance.component.version = "1.0"; + fixture.componentInstance.component.uuid = "a8cf015e-e4e5-4d4b-a01e-8624e8d36095"; + fixture.componentInstance.initEditResourceVersion(fixture.componentInstance.component, fixture.componentInstance.flatLeftPaletteElementsFromService(leftPaletteElements)); + expect(fixture.componentInstance.versions).toHaveLength(1); + }); + }); + +}); diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/info-tab/info-tab.component.ts b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/info-tab/info-tab.component.ts new file mode 100644 index 0000000000..45f31e7b35 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/info-tab/info-tab.component.ts @@ -0,0 +1,189 @@ +import { Component, OnInit, Input, Inject, OnDestroy } from '@angular/core'; +import { + PolicyInstance, + GroupInstance, + Component as TopologyTemplate, + ComponentInstance, + LeftPaletteComponent, + FullComponentInstance +} from "app/models"; +import {Store} from "@ngxs/store"; +import { EVENTS, GRAPH_EVENTS } from 'app/utils'; +import {IDropDownOption} from "onap-ui-angular/dist/form-elements/dropdown/dropdown-models"; +import { CompositionPaletteService } from "app/ng2/pages/composition/palette/services/palette.service"; +import { SdcUiCommon, SdcUiComponents, SdcUiServices } from "onap-ui-angular"; +import { SdcMenuToken, IAppMenu } from "app/ng2/config/sdc-menu.config"; +import { CompositionService } from "app/ng2/pages/composition/composition.service"; +import { ServiceServiceNg2 } from "app/services-ng2"; +import { WorkspaceService } from "app/ng2/pages/workspace/workspace.service"; +import { ComponentInstanceServiceNg2 } from "app/ng2/services/component-instance-services/component-instance.service"; +import { EventListenerService } from "app/services"; +import * as _ from 'lodash'; +import {SelectedComponentType, TogglePanelLoadingAction} from "../../../common/store/graph.actions"; +import Dictionary = _.Dictionary; + + +@Component({ + selector: 'panel-info-tab', + templateUrl: './info-tab.component.html', + styleUrls: ['./info-tab.component.less'], + // providers: [SdcUiServices.ModalService] +}) +export class InfoTabComponent implements OnInit, OnDestroy { + + @Input() isViewOnly: boolean; + @Input() componentType: SelectedComponentType; + @Input() component: TopologyTemplate | PolicyInstance | GroupInstance | ComponentInstance; + public versions: IDropDownOption[]; + private leftPalletElements: LeftPaletteComponent[]; + private isDisabledFlag: boolean; + private isComponentSelectedFlag: boolean; + + constructor(private store: Store, + private compositionPaletteService: CompositionPaletteService, + private compositionService: CompositionService, + private workspaceService: WorkspaceService, + private modalService: SdcUiServices.ModalService, + private componentInstanceService: ComponentInstanceServiceNg2, + private serviceService: ServiceServiceNg2, + private eventListenerService: EventListenerService, + @Inject(SdcMenuToken) public sdcMenu:IAppMenu) { + } + + ngOnInit() { + this.leftPalletElements = this.flatLeftPaletteElementsFromService(this.compositionPaletteService.getLeftPaletteElements()); + this.initEditResourceVersion(this.component, this.leftPalletElements); + this.eventListenerService.registerObserverCallback(EVENTS.ON_CHECKOUT, (comp) => { + this.component = comp; + }); + this.isComponentSelectedFlag = this.isComponentInstanceSelected(); + this.isDisabledFlag = this.isDisabled(); + + } + + ngOnDestroy() { + this.eventListenerService.unRegisterObserver(EVENTS.ON_CHECKOUT); + } + + flatLeftPaletteElementsFromService = (leftPalleteElementsFromService: Dictionary>): LeftPaletteComponent[] => { + let retValArr = []; + for (const category in leftPalleteElementsFromService) { + for (const subCategory in leftPalleteElementsFromService[category]) { + retValArr = retValArr.concat(leftPalleteElementsFromService[category][subCategory].slice(0)); + } + } + return retValArr; + } + + private isComponentInstanceSelected () { + return this.componentType === SelectedComponentType.COMPONENT_INSTANCE; + } + + private versioning: Function = (versionNumber: string): string => { + let version: Array = versionNumber && versionNumber.split('.'); + return '00000000'.slice(version[0].length) + version[0] + '.' + '00000000'.slice(version[1].length) + version[1]; + }; + + + private onChangeVersion = (versionDropdown) => { + let newVersionValue = versionDropdown.value; + versionDropdown.value = (this.component).getComponentUid(); + + this.store.dispatch(new TogglePanelLoadingAction({isLoading: true})); + + // let service = this.$scope.currentComponent; + if(this.component instanceof FullComponentInstance) { + + let onCancel = (error:any) => { + this.store.dispatch(new TogglePanelLoadingAction({isLoading: false})); + if (error) { + console.log(error); + } + }; + + let onUpdate = () => { + //this function will update the instance version than the function call getComponent to update the current component and return the new instance version + this.componentInstanceService.changeResourceInstanceVersion(this.workspaceService.metadata.componentType, this.workspaceService.metadata.uniqueId, this.component.uniqueId, newVersionValue) + .subscribe((component) => { + this.store.dispatch(new TogglePanelLoadingAction({isLoading: false})); + this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_VERSION_CHANGED, component); + }, onCancel); + }; + + if (this.component.isService() || this.component.isServiceProxy()) { + this.serviceService.checkComponentInstanceVersionChange(this.workspaceService.metadata.componentType, this.workspaceService.metadata.uniqueId, + this.component.uniqueId, newVersionValue).subscribe((pathsToDelete:string[]) => { + if (pathsToDelete && pathsToDelete.length) { + this.store.dispatch(new TogglePanelLoadingAction({isLoading: false})); + + + const {title, message} = this.sdcMenu.alertMessages['upgradeInstance']; + let pathNames:string = this.getPathNamesVersionChangeModal(pathsToDelete); + let onOk: Function = () => { + this.store.dispatch(new TogglePanelLoadingAction({isLoading: true})); + + onUpdate(); + }; + const okButton = {testId: "OK", text: "OK", type: SdcUiCommon.ButtonType.info, callback: onOk, closeModal: true} as SdcUiComponents.ModalButtonComponent; + const cancelButton = {testId: "Cancel", text: "Cancel", type: SdcUiCommon.ButtonType.secondary, callback: onCancel, closeModal: true} as SdcUiComponents.ModalButtonComponent; + const modal = this.modalService.openInfoModal(title, message.format([pathNames]), 'confirm-modal', [okButton, cancelButton]); + modal.getCloseButton().onClick(onCancel); + } else { + onUpdate(); + } + }, onCancel); + } else { + onUpdate(); + } + } + }; + + + private getPathNamesVersionChangeModal = (pathsToDelete:string[]):string => { + const relatedPaths = _.filter(this.compositionService.forwardingPaths, path => + _.find(pathsToDelete, id => + path.uniqueId === id + ) + ).map(path => path.name); + const pathNames = _.join(relatedPaths, ', ') || 'none'; + return pathNames; + }; + + + private initEditResourceVersion = (component, leftPaletteComponents): void => { + if(this.component instanceof ComponentInstance) { + + this.versions = []; + let sorted:any = _.sortBy(_.toPairs(component.allVersions), (item) => { + return item[0] !== "undefined" && this.versioning(item[0]); + }); + _.forEach(sorted, (item) => { + this.versions.push({label: item[0], value: item[1]}); + }); + + let highestVersion = _.last(sorted)[0]; + + if (parseFloat(highestVersion) % 1) { //if highest is minor, make sure it is the latest checked in - + let latestVersionComponent: LeftPaletteComponent = _.maxBy( + _.filter(leftPaletteComponents, (leftPaletteComponent: LeftPaletteComponent) => { //latest checked in + return (leftPaletteComponent.systemName === component.systemName || leftPaletteComponent.uuid === component.uuid); + }) + , (component) => { + return component.version + }); + + let latestVersion: string = latestVersionComponent ? latestVersionComponent.version : highestVersion; + + if (latestVersion && highestVersion != latestVersion) { //highest is checked out - remove from options + this.versions = this.versions.filter(version => version.label != highestVersion); + } + } + } + } + + private isDisabled() { + return this.isViewOnly || this.component['archived'] || this.component['resourceType'] === 'CVFC' + } + +}; + diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/panel-tab.component.ts b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/panel-tab.component.ts new file mode 100644 index 0000000000..c148a4e579 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/panel-tab.component.ts @@ -0,0 +1,55 @@ +import { NgModule, Component, Compiler, ViewContainerRef, ViewChild, Input, ComponentRef, ComponentFactoryResolver, ChangeDetectorRef } from '@angular/core'; +import {Component as TopologyTemplate} from "app/models"; +import { SdcUiServices } from "onap-ui-angular"; + +// Helper component to add dynamic tabs +@Component({ + selector: 'panel-tab', + template: `
` +}) +export class PanelTabComponent { + @ViewChild('content', { read: ViewContainerRef }) content; + @Input() isActive:boolean; + @Input() panelTabType; + @Input() input; + @Input() isViewOnly:boolean; + @Input() component:TopologyTemplate; + @Input() componentType; + cmpRef: ComponentRef; + private isViewInitialized: boolean = false; + + constructor(private componentFactoryResolver: ComponentFactoryResolver, + private cdRef: ChangeDetectorRef) { } + + updateComponent() { + if (!this.isViewInitialized || !this.isActive) { + return; + } + if (this.cmpRef) { + this.cmpRef.destroy(); + } + + let factory = this.componentFactoryResolver.resolveComponentFactory(this.panelTabType); + this.cmpRef = this.content.createComponent(factory); + this.cmpRef.instance.input = this.input; + this.cmpRef.instance.isViewOnly = this.isViewOnly; + this.cmpRef.instance.component = this.component; + this.cmpRef.instance.componentType = this.componentType; + this.cdRef.detectChanges(); + } + + ngOnChanges() { + this.updateComponent(); + } + + ngAfterViewInit() { + this.isViewInitialized = true; + this.updateComponent(); + } + + ngOnDestroy() { + if (this.cmpRef) { + this.cmpRef.destroy(); + } + } +} \ No newline at end of file diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/panel-tabs.less b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/panel-tabs.less new file mode 100644 index 0000000000..b3c03f85c5 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/panel-tabs.less @@ -0,0 +1,65 @@ +@import '../../../../../../assets/styles/variables'; +@import '../../../../../../assets/styles/override'; + + +// --------------------------------------------------------------------------------------------------- +///* override sdc-ui library tabs */ +// --------------------------------------------------------------------------------------------------- + + +:host ::ng-deep .sdc-tabs { + + .sdc-tabs-list { + display: flex; + border-bottom: 1px solid @sdcui_color_silver; + min-height: min-content; + } + .sdc-tab { + background-color: @sdcui_color_white; + border: 1px solid @sdcui_color_silver; + border-left: none; + border-bottom: none; + height: 36px; + width: 60px; + display: flex; + align-content: center; + justify-content: center; + cursor: pointer; + padding: 0; + margin: 0; + + + &.sdc-tab-active { + background-color: @sdcui_color_silver; + border-bottom: none; + } + &[disabled] { + opacity: 0.3; + cursor: default; + } + } + &.sdc-tabs-header { + .sdc-tab { + font-size: 24px; + } + } + &.sdc-tabs-menu { + .sdc-tab { + font-size: 14px; + padding: 0px 10px 4px 10px; + } + } + .sdc-tab-content { + margin-top: 0; + flex:1; + overflow-y:auto; + } +} + + +:host ::ng-deep .expand-collapse-title { + margin-top: 1px; + background-color: #eaeaea; + color: #5a5a5a; + font-family: OpenSans-Semibold, sans-serif; +} diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-information-tab.component.html b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-information-tab.component.html deleted file mode 100644 index 2a1c58c4cf..0000000000 --- a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-information-tab.component.html +++ /dev/null @@ -1,50 +0,0 @@ - - - -
General Info
- - -
- - {{policy.policyTypeUid}} -
- - -
- - Policy -
- - -
- - Policy -
- - -
- - {{policy.version}} -
- - -
- - {{policy.description}} -
-
-
diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-information-tab.component.ts b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-information-tab.component.ts deleted file mode 100644 index 3639639c88..0000000000 --- a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-information-tab.component.ts +++ /dev/null @@ -1,39 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * SDC - * ================================================================================ - * Copyright (C) 2017 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. - * ============LICENSE_END========================================================= - */ - -import * as _ from "lodash"; -import { Component, Inject, Input, Output, EventEmitter } from "@angular/core"; -import { TranslateService } from './../../../../../shared/translator/translate.service'; -import { PolicyInstance } from 'app/models/graph/zones/policy-instance'; - -@Component({ - selector: 'policy-information-tab', - templateUrl: './policy-information-tab.component.html', - styleUrls: ['./../base/base-tab.component.less'] -}) -export class PolicyInformationTabComponent { - - @Input() policy:PolicyInstance; - @Input() isViewOnly: boolean; - - constructor(private translateService:TranslateService) { - } - -} diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-properties-tab.component.html b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-properties-tab.component.html deleted file mode 100644 index fe1f6b4f0d..0000000000 --- a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-properties-tab.component.html +++ /dev/null @@ -1,39 +0,0 @@ - - - -
Properties
- -
    -
  • -
    {{property.name}} -
    -
    {{property.value || property.defaultValue}} -
    -
  • -
- -
-
No properties to display
-
-
-
diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-properties-tab.component.less b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-properties-tab.component.less deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-properties-tab.component.ts b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-properties-tab.component.ts deleted file mode 100644 index 5862135df2..0000000000 --- a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-properties-tab.component.ts +++ /dev/null @@ -1,64 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * SDC - * ================================================================================ - * Copyright (C) 2017 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. - * ============LICENSE_END========================================================= - */ - -import * as _ from "lodash"; -import { Component, Inject, Input, Output, EventEmitter, OnChanges, SimpleChanges } from "@angular/core"; -import { TranslateService } from './../../../../../shared/translator/translate.service'; -import { PolicyInstance } from 'app/models/graph/zones/policy-instance'; -import { PropertyBEModel } from 'app/models'; -import { PropertyModel } from './../../../../../../models/properties'; -import { ModalsHandler } from "app/utils"; -import { Component as TopologyTemplate, ComponentInstance, IAppMenu } from "app/models"; - -@Component({ - selector: 'policy-properties-tab', - templateUrl: './policy-properties-tab.component.html', - styleUrls: ['./../base/base-tab.component.less', 'policy-properties-tab.component.less'], - host: {'class': 'component-details-panel-tab-policy-properties'} -}) -export class PolicyPropertiesTabComponent implements OnChanges { - - @Input() policy:PolicyInstance; - @Input() topologyTemplate:TopologyTemplate; - @Input() isViewOnly: boolean; - - private properties:Array; - - constructor(private translateService:TranslateService, private ModalsHandler:ModalsHandler) { - } - - ngOnChanges(changes: SimpleChanges): void { - console.log("PolicyPropertiesTabComponent: ngAfterViewInit: "); - console.log("policy: " + this.policy); - this.properties = []; - this.initProperties(); - } - - initProperties = ():void => { - this.properties= this.policy.properties; - } - - editProperty = (property?:PropertyModel):void => { - this.ModalsHandler.openEditPropertyModal((property ? property : new PropertyModel()), this.topologyTemplate, this.properties, false, 'policy', this.policy.uniqueId).then((updatedProperty:PropertyModel) => { - console.log("ok"); - }); - } - -} diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-tabs.component.html b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-tabs.component.html deleted file mode 100644 index 8d1730f68c..0000000000 --- a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-tabs.component.html +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - - - - - - diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-tabs.component.ts b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-tabs.component.ts deleted file mode 100644 index 1e2739901d..0000000000 --- a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-tabs.component.ts +++ /dev/null @@ -1,72 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * SDC - * ================================================================================ - * Copyright (C) 2017 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. - * ============LICENSE_END========================================================= - */ - -import * as _ from "lodash"; -import { Component, Inject, Input, Output, EventEmitter, AfterViewInit, OnChanges } from "@angular/core"; -import { TranslateService } from './../../../../../shared/translator/translate.service'; -import { PoliciesService } from "../../../../../services/policies.service"; -import { Component as TopologyTemplate, ComponentInstance, IAppMenu } from "app/models"; -import { PolicyInstance } from 'app/models/graph/zones/policy-instance'; -import { GRAPH_EVENTS } from './../../../../../../utils/constants'; -import { EventListenerService } from 'app/services/event-listener-service'; -import { ZoneInstance } from 'app/models/graph/zones/zone-instance'; -import { SimpleChanges } from "@angular/core/src/metadata/lifecycle_hooks"; - -@Component({ - selector: 'policy-tabs', - templateUrl: './policy-tabs.component.html' -}) -export class PolicyTabsComponent implements OnChanges { - - @Input() topologyTemplate:TopologyTemplate; - @Input() selectedZoneInstanceType:string; - @Input() selectedZoneInstanceId:string; - @Input() isViewOnly: boolean; - @Output() isLoading: EventEmitter = new EventEmitter(); - - private policy:PolicyInstance; - - constructor(private translateService:TranslateService, - private policiesService:PoliciesService - ) { - - } - - ngOnChanges(changes: SimpleChanges): void { - this.initPolicy(); - } - - private initPolicy = ():void => { - this.isLoading.emit(true); - this.policiesService.getSpecificPolicy(this.topologyTemplate.componentType, this.topologyTemplate.uniqueId, this.selectedZoneInstanceId).subscribe( - policy => { - this.policy = policy; - console.log(JSON.stringify(policy)); - }, - error => console.log("Error getting policy!"), - () => this.isLoading.emit(false) - ); - } - - private setIsLoading = (value) :void => { - this.isLoading.emit(value); - } - -} diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-tabs.module.ts b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-tabs.module.ts deleted file mode 100644 index 38dc19e1af..0000000000 --- a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-tabs.module.ts +++ /dev/null @@ -1,68 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * SDC - * ================================================================================ - * Copyright (C) 2017 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. - * ============LICENSE_END========================================================= - */ -import { NgModule } from "@angular/core"; -import { HttpModule } from "@angular/http"; -import { FormsModule } from "@angular/forms"; -import { BrowserModule } from "@angular/platform-browser"; -import { UiElementsModule } from 'app/ng2/components/ui/ui-elements.module'; -import { ExpandCollapseComponent } from 'app/ng2/components/ui/expand-collapse/expand-collapse.component'; -import { PoliciesService } from "../../../../../services/policies.service"; -import { PolicyInformationTabComponent } from "./policy-information-tab.component"; -import { PolicyTargetsTabComponent } from "./policy-targets-tab.component"; -import { PolicyTabsComponent } from "./policy-tabs.component"; -import { PolicyPropertiesTabComponent } from "./policy-properties-tab.component"; -import { SdcUiComponentsModule } from "sdc-ui/lib/angular"; -import { TranslateModule } from './../../../../../shared/translator/translate.module'; - -@NgModule({ - declarations: [ - PolicyInformationTabComponent, - PolicyTargetsTabComponent, - PolicyPropertiesTabComponent, - PolicyTabsComponent - ], - imports: [ - BrowserModule, - FormsModule, - HttpModule, - SdcUiComponentsModule, - TranslateModule, - UiElementsModule - ], - entryComponents: [ - PolicyInformationTabComponent, - PolicyTargetsTabComponent, - PolicyPropertiesTabComponent, - PolicyTabsComponent, - ExpandCollapseComponent - ], - exports: [ - PolicyInformationTabComponent, - PolicyTargetsTabComponent, - PolicyPropertiesTabComponent, - PolicyTabsComponent - ], - providers: [ - PoliciesService - ] -}) -export class PolicyTabsModule { - -} diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-targets-tab.component.html b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-targets-tab.component.html deleted file mode 100644 index e263836fb1..0000000000 --- a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-targets-tab.component.html +++ /dev/null @@ -1,48 +0,0 @@ - - -
Targets - - -
-
-
    -
  • - {{target.name}} - -
  • -
- -
-
No data to display yet
-
Add targets to policy to see targets
-
-
- diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-targets-tab.component.less b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-targets-tab.component.less deleted file mode 100644 index cd7ace2b6f..0000000000 --- a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-targets-tab.component.less +++ /dev/null @@ -1,12 +0,0 @@ -/deep/ -.component-details-panel-tab-policy-targets { - .component-details-panel-large-item { - display: flex; - flex-direction: row; - justify-content: space-between; - } - .w-sdc-designer-sidebar-section-title { - display: flex; - justify-content: space-between; - } -} \ No newline at end of file diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-targets-tab.component.ts b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-targets-tab.component.ts deleted file mode 100644 index b79f4d9e07..0000000000 --- a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-targets-tab.component.ts +++ /dev/null @@ -1,145 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * SDC - * ================================================================================ - * Copyright (C) 2017 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. - * ============LICENSE_END========================================================= - */ - -import * as _ from "lodash"; -import { Component, Input, Output, EventEmitter, OnChanges, HostBinding, OnDestroy } from "@angular/core"; -import { TranslateService } from './../../../../../shared/translator/translate.service'; -import { Component as TopologyTemplate } from "app/models"; -import { PoliciesService } from "../../../../../services/policies.service"; -import { PolicyInstance, PolicyTargetsMap } from './../../../../../../models/graph/zones/policy-instance'; -import { SimpleChanges } from "@angular/core/src/metadata/lifecycle_hooks"; -import { SdcUiComponents } from "sdc-ui/lib/angular"; -import { IModalConfig } from "sdc-ui/lib/angular/modals/models/modal-config"; -import { AddElementsComponent } from "../../../../../components/ui/modal/add-elements/add-elements.component"; -import { TargetUiObject } from "../../../../../../models/ui-models/ui-target-object"; -import { ComponentInstance } from "../../../../../../models/componentsInstances/componentInstance"; -import { TargetOrMemberType } from "../../../../../../utils/constants"; -import { GRAPH_EVENTS } from 'app/utils'; -import { EventListenerService } from 'app/services/event-listener-service'; - -@Component({ - selector: 'policy-targets-tab', - templateUrl: './policy-targets-tab.component.html', - styleUrls: ['./../base/base-tab.component.less', 'policy-targets-tab.component.less'] -}) - -export class PolicyTargetsTabComponent implements OnChanges, OnDestroy { - - private targets: Array; // UI object to hold all targets with names. - - @Input() policy: PolicyInstance; - @Input() topologyTemplate: TopologyTemplate; - @Input() isViewOnly: boolean; - @Output() isLoading: EventEmitter = new EventEmitter(); - @HostBinding('class') classes = 'component-details-panel-tab-policy-targets'; - - constructor(private translateService: TranslateService, - private policiesService: PoliciesService, - private modalService: SdcUiComponents.ModalService, - private eventListenerService: EventListenerService - ) { - this.eventListenerService.registerObserverCallback(GRAPH_EVENTS.ON_POLICY_INSTANCE_UPDATE, this.initTargets) - } - - ngOnChanges(changes:SimpleChanges):void { - this.initTargets(); - } - - ngOnDestroy() { - this.eventListenerService.unRegisterObserver(GRAPH_EVENTS.ON_POLICY_INSTANCE_UPDATE); - } - - deleteTarget(target: TargetUiObject): void { - this.isLoading.emit(true); - this.policiesService.deletePolicyTarget(this.topologyTemplate.componentType, this.topologyTemplate.uniqueId, this.policy, target.uniqueId, target.type).subscribe( - (policyInstance:PolicyInstance) => { - this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_POLICY_INSTANCE_UPDATE, policyInstance); - }, - error => console.log("Error deleting target!"), - () => this.isLoading.emit(false) - ); - } - - private initTargets = (policyInstance?: PolicyInstance) => { - this.policy = policyInstance ? policyInstance : this.policy; - this.targets = this.policy.getTargetsAsUiObject(this.topologyTemplate.componentInstances, this.topologyTemplate.groupInstances); - } - - addTargets = ():void => { - - var targetsToAdd:Array = this.modalService.getCurrentInstance().innerModalContent.instance.existingElements; //TODO refactor sdc-ui modal in order to return the data - if(targetsToAdd.length > 0) { - this.modalService.closeModal(); - this.isLoading.emit(true); - var updatedTarget: Array = _.union(this.targets, targetsToAdd); - this.policiesService.updateTargets(this.topologyTemplate.componentType, this.topologyTemplate.uniqueId, this.policy.uniqueId, updatedTarget).subscribe( - (updatedPolicyInstance:PolicyInstance) => { - this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_POLICY_INSTANCE_UPDATE, updatedPolicyInstance); - }, - error => { - console.log("Error updating targets!"); - }, - () => this.isLoading.emit(false) - ); - } - } - - getOptionalsTargetsToAdd():Array { - let optionalsTargetsToAdd:Array = []; - // adding all instances as optional targets to add if not already exist - _.forEach(this.topologyTemplate.componentInstances, (instance:ComponentInstance) => { - if (!_.some(this.targets, (target:TargetUiObject) => { - return target.uniqueId === instance.uniqueId - })) { - optionalsTargetsToAdd.push(new TargetUiObject(instance.uniqueId, TargetOrMemberType.COMPONENT_INSTANCES, instance.name)); - } - }); - - // adding all groups as optional targets to add if not already exist - _.forEach(this.topologyTemplate.groupInstances, (groupInstance:ComponentInstance) => { // adding all instances as optional targets to add if not already exist - if (!_.some(this.targets, (target:TargetUiObject) => { - return target.uniqueId === groupInstance.uniqueId - })) { - optionalsTargetsToAdd.push(new TargetUiObject(groupInstance.uniqueId, TargetOrMemberType.GROUPS, groupInstance.name)); - } - }); - - return optionalsTargetsToAdd; - } - - openAddTargetModal(): void { - let addTargetModalConfig: IModalConfig = { - title: this.policy.name + " ADD TARGETS", - size: "md", - type: "custom", - testId: "addTargetsModal", - buttons: [ - {text: "ADD TARGETS", size: 'xsm', callback: this.addTargets, closeModal: false}, - {text: 'CANCEL', size: 'sm', type: "secondary", closeModal: true} - ] - }; - var optionalTargetsToAdd = this.getOptionalsTargetsToAdd(); - this.modalService.openCustomModal(addTargetModalConfig, AddElementsComponent, { - elementsToAdd: optionalTargetsToAdd, - elementName: "target" - }); - - } -} diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policy-targets-tab/policy-targets-tab.component.html b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policy-targets-tab/policy-targets-tab.component.html new file mode 100644 index 0000000000..838fd8bb51 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policy-targets-tab/policy-targets-tab.component.html @@ -0,0 +1,48 @@ + + +

Targets + + +

+
+
    +
  • + {{target.name}} + +
  • +
+ +
+
No data to display yet
+
Add targets to policy to see targets
+
+
+ diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policy-targets-tab/policy-targets-tab.component.less b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policy-targets-tab/policy-targets-tab.component.less new file mode 100644 index 0000000000..d16a1595df --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policy-targets-tab/policy-targets-tab.component.less @@ -0,0 +1,61 @@ +@import './../../../../../../../assets/styles/mixins'; + + +.expand-collapse-content { + padding: 20px; +} + +.component-details-panel-tab-no-data { + margin: 0 auto; + padding-top: 30px; + text-align: center; + + .component-details-panel-tab-no-data-title { + font-family: @font-opensans-bold; + } + +} + +.component-details-panel-large-item { + font-family: OpenSans-Semibold, sans-serif; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + height: 32px; + line-height: 32px; + display: flex; + flex-direction: row; + justify-content: space-between; + + &:hover { + background-color: #f8f8f8; + margin: 0 -20px; /* to fill expand-collapse-content padding */ + padding: 0 20px; + .component-details-panel-item-delete { + visibility: visible; + } + } +} + +.component-details-panel-item-delete { + cursor: pointer; + visibility: hidden; +} + +/deep/ .w-sdc-designer-sidebar-section-title { + color: #5a5a5a; + font-family: OpenSans-Semibold, sans-serif; + font-size: 14px; + background-color: #eaeaea; + cursor: pointer; + display: flex; + justify-content: space-between; + align-items: center; + text-transform: uppercase; + line-height: 32px; + padding: 0 10px 0 20px; + margin-top: 1px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policy-targets-tab/policy-targets-tab.component.spec.ts b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policy-targets-tab/policy-targets-tab.component.spec.ts new file mode 100644 index 0000000000..7774138cab --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policy-targets-tab/policy-targets-tab.component.spec.ts @@ -0,0 +1,113 @@ +import { NO_ERRORS_SCHEMA } from '@angular/core'; +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { SdcUiCommon, SdcUiComponents, SdcUiServices } from 'onap-ui-angular'; +import { Observable } from 'rxjs/Rx'; +import { Mock } from 'ts-mockery'; +import { ConfigureFn, configureTests } from '../../../../../../../jest/test-config.helper'; +import { ComponentMetadata } from '../../../../../../models/component-metadata'; +import { EventListenerService } from '../../../../../../services/event-listener-service'; +import { TranslateService } from '../../../../../shared/translator/translate.service'; +import { WorkspaceService } from '../../../../workspace/workspace.service'; +import { CompositionService } from '../../../composition.service'; +import { PolicyTargetsTabComponent } from "app/ng2/pages/composition/panel/panel-tabs/policy-targets-tab/policy-targets-tab.component"; +import { PoliciesService } from "app/services-ng2"; +import { PolicyInstance, GroupInstance } from "app/models"; +import { NgxsModule } from "@ngxs/store"; +import { GraphState } from "app/ng2/pages/composition/common/store/graph.state"; +import { WorkspaceState } from "app/ng2/store/states/workspace.state"; +import { TargetUiObject } from "app/models/ui-models/ui-target-object"; +import { TargetOrMemberType } from "app/utils"; + + + + +describe('policy targets tab component', () => { + + let fixture: ComponentFixture; + let component: PolicyTargetsTabComponent; + + let policiesServiceMock = Mock.of( + { + updateTargets: jest.fn().mockImplementation((compType, uid, policyUniqueId, updatedTargets) => { + if (updatedTargets === undefined) { + return Observable.throwError('error'); + } else { + return Observable.of(updatedTargets); + } + } + )}); + + let compositionServiceMock = { + componentInstances: [{uniqueId: '1', name: 'inst1'}, + {uniqueId: '2', name: 'inst2'}, + {uniqueId: '3', name: 'inst3'}, + {uniqueId: '4', name: 'inst4'}, + {uniqueId: '5', name: 'inst5'} + ], + groupInstances : [ + Mock.of({uniqueId: "group1", name: "group1"}), + Mock.of({uniqueId: "group2", name: "group2"}), + Mock.of({uniqueId: "group3", name: "group3"}) + ] + }; + + let workspaceServiceMock = { + metadata: Mock.of() + }; + + let modalServiceMock = { + openInfoModal: jest.fn(), + openCustomModal: jest.fn().mockImplementation(() => { return { + innerModalContent: { instance: { existingElements: targetsToAdd }}, + closeModal: jest.fn() + }}) + }; + + let loaderServiceMock = { + activate: jest.fn(), + deactivate: jest.fn() + }; + + const targetsToAdd = [ + {uniqueId: '1', name: 'inst1', type: TargetOrMemberType.COMPONENT_INSTANCES}, + {uniqueId: "group1", name: "group1", type: TargetOrMemberType.GROUPS} + ]; + + const policyInstanceMock = Mock.of( + { getTargetsAsUiObject: jest.fn().mockImplementation( () => targetsToAdd) + }); + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [PolicyTargetsTabComponent], + imports: [NgxsModule.forRoot([WorkspaceState])], + schemas: [NO_ERRORS_SCHEMA], + providers: [ + {provide: TranslateService, useValue: { translate: jest.fn() }}, + {provide: PoliciesService, useValue: policiesServiceMock}, + {provide: SdcUiServices.ModalService, useValue: modalServiceMock }, + {provide: EventListenerService, useValue: {} }, + {provide: CompositionService, useValue: compositionServiceMock }, + {provide: WorkspaceService, useValue: workspaceServiceMock}, + {provide: SdcUiServices.LoaderService, useValue: loaderServiceMock } + ], + }); + + fixture = TestBed.createComponent(PolicyTargetsTabComponent); + component = fixture.componentInstance; + component.policy = policyInstanceMock; + }); + + + it('if there are no existing targets, all component instances AND all groups are available for adding', () => { + component.targets = []; + const optionalTargetsToAdd = component.getOptionalsTargetsToAdd(); + expect(optionalTargetsToAdd).toHaveLength(8); + }); + + it('list of available instances to add does not include existing targets', () => { + component.targets = targetsToAdd; + const optionalMembersToAdd = component.getOptionalsTargetsToAdd(); + expect(optionalMembersToAdd).toHaveLength(6); + }); +}); diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policy-targets-tab/policy-targets-tab.component.ts b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policy-targets-tab/policy-targets-tab.component.ts new file mode 100644 index 0000000000..f117290397 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policy-targets-tab/policy-targets-tab.component.ts @@ -0,0 +1,166 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 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. + * ============LICENSE_END========================================================= + */ + +import * as _ from "lodash"; +import { Component, Input, Output, EventEmitter, OnChanges, HostBinding, OnDestroy, OnInit } from "@angular/core"; +import { TranslateService } from './../../../../../shared/translator/translate.service'; +import { PoliciesService } from "../../../../../services/policies.service"; +import { PolicyInstance } from './../../../../../../models/graph/zones/policy-instance'; +import { SdcUiComponents, SdcUiCommon, SdcUiServices } from "onap-ui-angular"; +import { AddElementsComponent } from "../../../../../components/ui/modal/add-elements/add-elements.component"; +import { TargetUiObject } from "../../../../../../models/ui-models/ui-target-object"; +import { ComponentInstance } from "../../../../../../models/componentsInstances/componentInstance"; +import { TargetOrMemberType } from "../../../../../../utils/constants"; +import { GRAPH_EVENTS } from 'app/utils'; +import { EventListenerService } from 'app/services/event-listener-service'; +import { CompositionService } from "app/ng2/pages/composition/composition.service"; +import { WorkspaceService } from "app/ng2/pages/workspace/workspace.service"; +import { Store } from "@ngxs/store"; +import { Select } from "@ngxs/store"; +import { Observable } from "rxjs"; +import { tap } from "rxjs/operators"; +import {GraphState} from "../../../common/store/graph.state"; + +@Component({ + selector: 'policy-targets-tab', + templateUrl: './policy-targets-tab.component.html', + styleUrls: ['policy-targets-tab.component.less'] +}) + +export class PolicyTargetsTabComponent implements OnInit { + + @Input() input:any; + + + @Input() isViewOnly: boolean; + @HostBinding('class') classes = 'component-details-panel-tab-policy-targets'; + @Select(GraphState.getSelectedComponent) policy$: Observable; + public policy: PolicyInstance; + private subscription; + + private addModalInstance: SdcUiComponents.ModalComponent; + public targets: Array; // UI object to hold all targets with names. + + + constructor(private translateService: TranslateService, + private policiesService: PoliciesService, + private modalService: SdcUiServices.ModalService, + private eventListenerService: EventListenerService, + private compositionService: CompositionService, + private workspaceService: WorkspaceService, + private loaderService: SdcUiServices.LoaderService, + private store: Store + ) { } + + ngOnInit() { + this.subscription = this.policy$.pipe( + tap((policy) => { + if(policy instanceof PolicyInstance){ + this.policy = policy; + this.targets = this.policy.getTargetsAsUiObject(this.compositionService.componentInstances, this.compositionService.groupInstances); + } + })).subscribe(); + } + + ngOnDestroy () { + if(this.subscription) + this.subscription.unsubscribe(); + } + + deleteTarget(target: TargetUiObject): void { + this.loaderService.activate(); + this.policiesService.deletePolicyTarget(this.workspaceService.metadata.componentType, this.workspaceService.metadata.uniqueId, this.policy, target.uniqueId, target.type).subscribe( + (policyInstance:PolicyInstance) => { + this.targets = this.targets.filter(item => item.uniqueId !== target.uniqueId); + this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_POLICY_INSTANCE_UPDATE, policyInstance); + // this.store.dispatch(new UpdateSelectedComponentAction({uniqueId: policyInstance.uniqueId, type:ComponentType.})); + }, + error => { + console.log("Error deleting target!"); + this.loaderService.deactivate(); + }, + () => this.loaderService.deactivate() + ); + } + + + addTargets = ():void => { + + var targetsToAdd:Array = this.addModalInstance.innerModalContent.instance.existingElements; //TODO refactor sdc-ui modal in order to return the data + if(targetsToAdd.length > 0) { + this.addModalInstance.closeModal(); + this.loaderService.activate(); + var updatedTargets: Array = _.union(this.targets, targetsToAdd); + this.policiesService.updateTargets(this.workspaceService.metadata.componentType, this.workspaceService.metadata.uniqueId, this.policy.uniqueId, updatedTargets).subscribe( + (updatedPolicyInstance:PolicyInstance) => { + this.targets = updatedTargets; + this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_POLICY_INSTANCE_UPDATE, updatedPolicyInstance); + // this.store.dispatch(new UpdateSelectedComponentAction({component: updatedPolicyInstance})); + }, + error => { + console.log("Error updating targets!"); + this.loaderService.deactivate(); + }, + () => this.loaderService.deactivate() + ); + } + } + + getOptionalsTargetsToAdd():Array { + let optionalsTargetsToAdd:Array = []; + // adding all instances as optional targets to add if not already exist + _.forEach(this.compositionService.componentInstances, (instance:ComponentInstance) => { + if (!_.some(this.targets, (target:TargetUiObject) => { + return target.uniqueId === instance.uniqueId + })) { + optionalsTargetsToAdd.push(new TargetUiObject(instance.uniqueId, TargetOrMemberType.COMPONENT_INSTANCES, instance.name)); + } + }); + + // adding all groups as optional targets to add if not already exist + _.forEach(this.compositionService.groupInstances, (groupInstance:ComponentInstance) => { // adding all instances as optional targets to add if not already exist + if (!_.some(this.targets, (target:TargetUiObject) => { + return target.uniqueId === groupInstance.uniqueId + })) { + optionalsTargetsToAdd.push(new TargetUiObject(groupInstance.uniqueId, TargetOrMemberType.GROUPS, groupInstance.name)); + } + }); + + return optionalsTargetsToAdd; + } + + openAddTargetModal(): void { + let addTargetModalConfig = { + title: this.policy.name + " ADD TARGETS", + size: "md", + type: SdcUiCommon.ModalType.custom, + testId: "addTargetsModal", + buttons: [ + {text: "ADD TARGETS", size: 'xsm', callback: this.addTargets, closeModal: false}, + {text: 'CANCEL', size: 'sm', type: "secondary", closeModal: true} + ] + } as SdcUiCommon.IModalConfig; + var optionalTargetsToAdd = this.getOptionalsTargetsToAdd(); + this.addModalInstance = this.modalService.openCustomModal(addTargetModalConfig, AddElementsComponent, { + elementsToAdd: optionalTargetsToAdd, + elementName: "target" + }); + } +} diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/properties-tab/properties-tab.component.html b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/properties-tab/properties-tab.component.html new file mode 100644 index 0000000000..86c6fea1ef --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/properties-tab/properties-tab.component.html @@ -0,0 +1,97 @@ + +
{{input.title}}
+ +
+
+ + + + +
+
+ +
+ {{property.name}} + {{property.defaultValue}} + {{property.value}} +
+
+ +
+
+
+
+ +
+
+
+ {{getComponentInstanceNameFromInstanceByKey(InstanceProperties.key) + ' Properties'}} +
+
+
+
+
+
+ {{instanceProperty.name}} +
+
+ + {{instanceProperty.value === undefined ? instanceProperty.defaultValue : instanceProperty.value}} +
+
+
+
+
+
+ + + + + +
+
+
+ + +
+ + + +
+
+
+ {{attribute.name}} +
+
+ {{attribute.defaultValue}} + {{attribute.value}} +
+
+
+
+
+
+
+
+
diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/properties-tab/properties-tab.component.less b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/properties-tab/properties-tab.component.less new file mode 100644 index 0000000000..5cb0697da1 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/properties-tab/properties-tab.component.less @@ -0,0 +1,66 @@ +.scroll-container { + display: flex; + overflow-y: auto; +} + +.i-sdc-designer-sidebar-section-content-item-property-and-attribute { + color: #666666; + font-family: OpenSans-Semibold, sans-serif; + font-size: 14px; + border-bottom: 1px solid #cdcdcd; + min-height: 72px; + padding: 15px 10px 10px 18px; + // position: relative; + display:flex; + + .property-details { + flex:1; + } + + .property-buttons { + flex: 0 0 auto; + align-self: center; + } +} + +.i-sdc-designer-sidebar-section-content-item-property-and-attribute-label { + display: block; + font-weight: bold; + &:hover { + color: #3b7b9b; + } +} + +.i-sdc-designer-sidebar-section-content-item-property-and-attribute-label, .i-sdc-designer-sidebar-section-content-item-property-value { + overflow: hidden; + text-overflow: ellipsis; + max-width: 245px; + white-space: nowrap; + display: block; +} + + + +/deep/ .expand-collapse-content { + max-height: max-content; + padding: 10px 0; + + .sdc-accordion .sdc-accordion-header { + + background-color: #e6f6fb; + border-left: solid #009fdb 4px; + box-shadow: 0 0px 3px -1px rgba(0, 0, 0, 0.3); + margin-bottom: 2px; + width: auto; + height: auto; + padding: 10px; + color: #666666; + font-family: OpenSans-Semibold, sans-serif; + font-size: 14px; + + } + + /deep/.sdc-accordion .sdc-accordion-body { + padding-left: 0; + } +} \ No newline at end of file diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/properties-tab/properties-tab.component.ts b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/properties-tab/properties-tab.component.ts new file mode 100644 index 0000000000..b4b8248ed0 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/properties-tab/properties-tab.component.ts @@ -0,0 +1,212 @@ +import { Component, Input, OnInit } from '@angular/core'; +import { Store } from '@ngxs/store'; +import { + AttributeModel, + AttributesGroup, + Component as TopologyTemplate, + ComponentMetadata, + FullComponentInstance, + PropertiesGroup, + PropertyModel +} from 'app/models'; +import { CompositionService } from 'app/ng2/pages/composition/composition.service'; +import { WorkspaceService } from 'app/ng2/pages/workspace/workspace.service'; +import { GroupByPipe } from 'app/ng2/pipes/groupBy.pipe'; +import { ResourceNamePipe } from 'app/ng2/pipes/resource-name.pipe'; +import { TopologyTemplateService } from 'app/ng2/services/component-services/topology-template.service'; +import { ComponentGenericResponse } from 'app/ng2/services/responses/component-generic-response'; +import { TranslateService } from 'app/ng2/shared/translator/translate.service'; +import { ModalsHandler } from 'app/utils'; +import { SdcUiCommon, SdcUiComponents, SdcUiServices } from 'onap-ui-angular'; +import {SelectedComponentType, TogglePanelLoadingAction} from "../../../common/store/graph.actions"; + +@Component({ + selector: 'properties-tab', + templateUrl: './properties-tab.component.html', + styleUrls: ['./properties-tab.component.less'] +}) +export class PropertiesTabComponent implements OnInit { + attributes: AttributesGroup; + isComponentInstanceSelected: boolean; + properties: PropertiesGroup; + groupPropertiesByInstance: boolean; + propertiesMessage: string; + metadata: ComponentMetadata; + objectKeys = Object.keys; + + @Input() isViewOnly: boolean; + @Input() componentType: SelectedComponentType; + @Input() component: FullComponentInstance | TopologyTemplate; + @Input() input: {title: string}; + + constructor(private store: Store, + private workspaceService: WorkspaceService, + private compositionService: CompositionService, + private modalsHandler: ModalsHandler, + private topologyTemplateService: TopologyTemplateService, + private modalService: SdcUiServices.ModalService, + private translateService: TranslateService, + private groupByPipe: GroupByPipe) { + } + + ngOnInit() { + this.metadata = this.workspaceService.metadata; + this.isComponentInstanceSelected = this.componentType === SelectedComponentType.COMPONENT_INSTANCE; + this.getComponentInstancesPropertiesAndAttributes(); + } + + public isPropertyOwner = (): boolean => { + return this.component instanceof TopologyTemplate && this.component.isResource(); + } + + public updateProperty = (property: PropertyModel): void => { + this.openEditPropertyModal(property); + } + + public deleteProperty = (property: PropertyModel): void => { + + const onOk: Function = (): void => { + this.store.dispatch(new TogglePanelLoadingAction({isLoading: true})); + this.topologyTemplateService.deleteProperty(this.component.componentType, this.component.uniqueId, property.uniqueId) + .subscribe((response) => { + this.store.dispatch(new TogglePanelLoadingAction({isLoading: false})); + this.component.properties = this.component.properties.filter((prop) => prop.uniqueId !== property.uniqueId); + this.initComponentProperties(); + }, () => { + this.store.dispatch(new TogglePanelLoadingAction({isLoading: false})); + }); + }; + + const title: string = this.translateService.translate('PROPERTY_VIEW_DELETE_MODAL_TITLE'); + const message: string = this.translateService.translate('PROPERTY_VIEW_DELETE_MODAL_TEXT', {name: property.name}); + const okButton = { + testId: 'OK', + text: 'OK', + type: SdcUiCommon.ButtonType.info, + callback: onOk, + closeModal: true} as SdcUiComponents.ModalButtonComponent; + this.modalService.openInfoModal(title, message, 'delete-modal', [okButton]); + } + + public groupNameByKey = (key: string): string => { + switch (key) { + case 'derived': + return 'Derived'; + + case this.metadata.uniqueId: + return ResourceNamePipe.getDisplayName(this.metadata.name); + + default: + return this.getComponentInstanceNameFromInstanceByKey(key); + } + } + + public getComponentInstanceNameFromInstanceByKey = (key: string): string => { + let instanceName: string = ''; + const componentInstance = this.compositionService.getComponentInstances().find((item) => item.uniqueId === key); + if (key !== undefined && componentInstance) { + + instanceName = ResourceNamePipe.getDisplayName(componentInstance.name); + } + return instanceName; + } + + private getComponentInstancesPropertiesAndAttributes = () => { + this.topologyTemplateService.getComponentInstanceAttributesAndProperties( + this.workspaceService.metadata.uniqueId, + this.workspaceService.metadata.componentType) + .subscribe((genericResponse: ComponentGenericResponse) => { + this.compositionService.componentInstancesAttributes = genericResponse.componentInstancesAttributes || new AttributesGroup(); + this.compositionService.componentInstancesProperties = genericResponse.componentInstancesProperties; + this.initPropertiesAndAttributes(); + }); + } + + private initComponentProperties = (): void => { + let result: PropertiesGroup = {}; + + this.propertiesMessage = undefined; + this.groupPropertiesByInstance = false; + if (this.component instanceof FullComponentInstance) { + result[this.component.uniqueId] = _.orderBy(this.compositionService.componentInstancesProperties[this.component.uniqueId], ['name']); + if (this.component.originType === 'VF') { + this.groupPropertiesByInstance = true; + result[this.component.uniqueId] = Array.from(this.groupByPipe.transform(result[this.component.uniqueId], 'path')); + } + } else if (this.metadata.isService()) { + // Temporally fix to hide properties for service (UI stack when there are many properties) + result = this.compositionService.componentInstancesProperties; + this.propertiesMessage = 'Note: properties for service are disabled'; + } else { + const componentUid = this.component.uniqueId; + result[componentUid] = Array(); + const derived = Array(); + _.forEach(this.component.properties, (property: PropertyModel) => { + if (componentUid === property.parentUniqueId) { + result[componentUid].push(property); + } else { + property.readonly = true; + derived.push(property); + } + }); + if (derived.length) { + result['derived'] = derived; + } + this.objectKeys(result).forEach((key) => { result[key] = _.orderBy(result[key], ['name']); }); + } + this.properties = result; + } + + private initComponentAttributes = (): void => { + let result: AttributesGroup = {}; + + if (this.component) { + if (this.component instanceof FullComponentInstance) { + result[this.component.uniqueId] = this.compositionService.componentInstancesAttributes[this.component.uniqueId] || []; + } else if (this.metadata.isService()) { + result = this.compositionService.componentInstancesAttributes; + } else { + result[this.component.uniqueId] = (this.component as TopologyTemplate).attributes; + } + this.attributes = result; + this.objectKeys(this.attributes).forEach((key) => { + this.attributes[key] = _.orderBy(this.attributes[key], ['name']); + }); + + } + } + + /** + * This function is checking if the component is the value owner of the current property + * in order to notify the edit property modal which fields to disable + */ + private isPropertyValueOwner = (): boolean => { + return this.metadata.isService() || !!this.component; + } + + /** + * The function opens the edit property modal. + * It checks if the property is from the VF or from one of it's resource instances and sends the needed property list. + * For create property reasons an empty array is transferd + * + * @param property the wanted property to edit/create + */ + private openEditPropertyModal = (property: PropertyModel): void => { + this.modalsHandler.newOpenEditPropertyModal(property, + (this.isPropertyOwner() ? + this.properties[property.parentUniqueId] : + this.properties[property.resourceInstanceUniqueId]) || [], + this.isPropertyValueOwner(), 'component', property.resourceInstanceUniqueId).then((updatedProperty: PropertyModel) => { + if (updatedProperty) { + const oldProp = _.find(this.properties[updatedProperty.resourceInstanceUniqueId], + (prop: PropertyModel) => prop.uniqueId === updatedProperty.uniqueId); + oldProp.value = updatedProperty.value; + } + }); + } + + private initPropertiesAndAttributes = (): void => { + this.initComponentProperties(); + this.initComponentAttributes(); + } +} diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/req-capabilities-tab/req-capabilities-tab.component.html b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/req-capabilities-tab/req-capabilities-tab.component.html new file mode 100644 index 0000000000..27e05ec1f0 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/req-capabilities-tab/req-capabilities-tab.component.html @@ -0,0 +1,36 @@ +
+
+
+ +
+
{{capability.name}} 
+
{{capability.type}}
+
+
+
+
+ + + + +
+
+ + + + +
+
{{capability.name}} 
+
{{capability.type}}
+
+
+
+ + + + + + + +
+
diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/req-capabilities-tab/req-capabilities-tab.component.less b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/req-capabilities-tab/req-capabilities-tab.component.less new file mode 100644 index 0000000000..fe4573aadc --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/req-capabilities-tab/req-capabilities-tab.component.less @@ -0,0 +1,57 @@ + +/deep/.sdc-accordion { + margin-bottom: 0; + display: grid; + + .sdc-accordion-header { + background-color: #e6f6fb; + border-left: solid #009fdb 4px; + box-shadow: 0 0px 3px -1px rgba(0, 0, 0, 0.3); + margin-bottom: 2px; + width: auto; + height: auto; + padding: 10px; + color: #666666; + font-family: OpenSans-Semibold, sans-serif; + font-size: 14px; + } + + .sdc-accordion-body.open { + padding-left: 0; + padding-top: 0; + .sdc-accordion-header { /*Second level - nested accordion */ + background-color: #f8f8f8; + padding: 4px 20px 4px 37px; + border-bottom: 1px solid #d2d2d2; + border-left:none; + height: 30px; + } + } +} + + +.relations-details-container { + border-bottom: 1px solid #cdcdcd; + padding: 10px 10px 10px 18px; + + font-size: 14px; + font-family: OpenSans-Regular, sans-serif; + + .relations-name { + color: #666666; + font-weight: bold; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + text-transform: capitalize; + max-width: 240px; + display: inline-block; + } + + .relations-desc { + color: #8c8c8c; + word-wrap: break-word; + white-space: normal; + max-width: 265px; + } +} \ No newline at end of file diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/req-capabilities-tab/req-capabilities-tab.component.ts b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/req-capabilities-tab/req-capabilities-tab.component.ts new file mode 100644 index 0000000000..03697b38f2 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/req-capabilities-tab/req-capabilities-tab.component.ts @@ -0,0 +1,165 @@ +import { Component, OnInit, Input, OnDestroy } from '@angular/core'; +import { Component as TopologyTemplate, Capability, Requirement, CapabilitiesGroup, RequirementsGroup, ComponentInstance, FullComponentInstance } from "app/models"; +import { Store } from "@ngxs/store"; +import { GRAPH_EVENTS } from "app/utils"; +import { ComponentGenericResponse } from "app/ng2/services/responses/component-generic-response"; +import { TopologyTemplateService } from "app/ng2/services/component-services/topology-template.service"; +import { EventListenerService } from "app/services"; +import { WorkspaceService } from "app/ng2/pages/workspace/workspace.service"; +import { CompositionService } from "app/ng2/pages/composition/composition.service"; +import {SelectedComponentType, TogglePanelLoadingAction} from "../../../common/store/graph.actions"; + + +export class InstanceCapabilitiesMap { + [key:string]:Array; +} + +export class InstanceRequirementsMap { + [key:string]:Array; +} + +@Component({ + selector: 'req-capabilities-tab', + templateUrl: './req-capabilities-tab.component.html', + styleUrls: ['./req-capabilities-tab.component.less'] +}) +export class ReqAndCapabilitiesTabComponent implements OnInit, OnDestroy { + + isComponentInstanceSelected: boolean; + capabilities:Array; + requirements:Array; + capabilitiesInstancesMap:InstanceCapabilitiesMap; + requirementsInstancesMap:InstanceRequirementsMap; + objectKeys = Object.keys; + + @Input() isViewOnly: boolean; + @Input() componentType: SelectedComponentType; + @Input() component: TopologyTemplate | FullComponentInstance; + @Input() input: any; + + + constructor(private store: Store, + private topologyTemplateService:TopologyTemplateService, + private workspaceService: WorkspaceService, + private compositionService: CompositionService, + private eventListenerService:EventListenerService) { } + + ngOnInit(): void { + + this.isComponentInstanceSelected = this.componentType === SelectedComponentType.COMPONENT_INSTANCE; + + this.requirements = []; + this.capabilities = []; + this.initEvents(); + this.initRequirementsAndCapabilities(); + + } + + private initEvents = ():void => { + this.eventListenerService.registerObserverCallback(GRAPH_EVENTS.ON_NODE_SELECTED, this.initRequirementsAndCapabilities); + this.eventListenerService.registerObserverCallback(GRAPH_EVENTS.ON_GRAPH_BACKGROUND_CLICKED, this.updateRequirementCapabilities); + this.eventListenerService.registerObserverCallback(GRAPH_EVENTS.ON_CREATE_COMPONENT_INSTANCE, this.updateRequirementCapabilities); + this.eventListenerService.registerObserverCallback(GRAPH_EVENTS.ON_DELETE_COMPONENT_INSTANCE, this.updateRequirementCapabilities); + } + + ngOnDestroy(): void { + this.eventListenerService.unRegisterObserver(GRAPH_EVENTS.ON_NODE_SELECTED, this.initRequirementsAndCapabilities); + this.eventListenerService.unRegisterObserver(GRAPH_EVENTS.ON_GRAPH_BACKGROUND_CLICKED, this.updateRequirementCapabilities); + this.eventListenerService.unRegisterObserver(GRAPH_EVENTS.ON_CREATE_COMPONENT_INSTANCE, this.updateRequirementCapabilities); + this.eventListenerService.unRegisterObserver(GRAPH_EVENTS.ON_DELETE_COMPONENT_INSTANCE, this.updateRequirementCapabilities); + } + + public isCurrentDisplayComponentIsComplex = ():boolean => { + + if (this.component instanceof FullComponentInstance) { + if (this.component.originType === 'VF') { + return true; + } + return false; + } else { + return this.component.isComplex(); + } + } + + private loadComplexComponentData = () => { + this.store.dispatch(new TogglePanelLoadingAction({isLoading: true})); + + this.topologyTemplateService.getCapabilitiesAndRequirements(this.workspaceService.metadata.componentType, this.workspaceService.metadata.uniqueId).subscribe((response:ComponentGenericResponse) => { + this.workspaceService.metadata.capabilities = response.capabilities; + this.workspaceService.metadata.requirements = response.requirements; + this.setScopeCapabilitiesRequirements(response.capabilities, response.requirements); + this.initInstancesMap(); + this.store.dispatch(new TogglePanelLoadingAction({isLoading: false})); + }, (error) => { this.store.dispatch(new TogglePanelLoadingAction({isLoading: false})); }); + } + + + private extractValuesFromMap = (map:CapabilitiesGroup | RequirementsGroup):Array => { + let values = []; + _.forEach(map, (capabilitiesOrRequirements:Array | Array, key) => { + values = values.concat(capabilitiesOrRequirements) + } + ); + return values; + } + + private setScopeCapabilitiesRequirements = (capabilities:CapabilitiesGroup, requirements:RequirementsGroup) => { + this.capabilities = this.extractValuesFromMap(capabilities); + this.requirements = this.extractValuesFromMap(requirements); + } + + + private initInstancesMap = ():void => { + + this.capabilitiesInstancesMap = new InstanceCapabilitiesMap(); + _.forEach(this.capabilities, (capability:Capability) => { + if (this.capabilitiesInstancesMap[capability.ownerName]) { + this.capabilitiesInstancesMap[capability.ownerName] = this.capabilitiesInstancesMap[capability.ownerName].concat(capability); + } else { + this.capabilitiesInstancesMap[capability.ownerName] = new Array(capability); + } + }); + + this.requirementsInstancesMap = new InstanceRequirementsMap(); + _.forEach(this.requirements, (requirement:Requirement) => { + if (this.requirementsInstancesMap[requirement.ownerName]) { + this.requirementsInstancesMap[requirement.ownerName] = this.requirementsInstancesMap[requirement.ownerName].concat(requirement); + } else { + this.requirementsInstancesMap[requirement.ownerName] = new Array(requirement); + } + }); + } + + private initRequirementsAndCapabilities = (needUpdate?: boolean) => { + + // if instance selected, we take the requirement and capabilities of the instance - always exist because we load them with the graph + if (this.component instanceof FullComponentInstance) { + this.store.dispatch(new TogglePanelLoadingAction({isLoading: false})); + this.setScopeCapabilitiesRequirements(this.component.capabilities, this.component.requirements); + if (this.component.originType === 'VF') { + this.initInstancesMap(); + } + } else { + // if instance not selected, we take the requirement and capabilities of the VF/SERVICE, if not exist we call api + if (needUpdate || !this.component.capabilities || !this.component.requirements) { + this.loadComplexComponentData(); + + } else { + this.store.dispatch(new TogglePanelLoadingAction({isLoading: false})); + this.setScopeCapabilitiesRequirements(this.component.capabilities, this.component.requirements); + this.initInstancesMap(); + } + } + } + + private updateRequirementCapabilities = () => { + if (!this.isComponentInstanceSelected) { + this.loadComplexComponentData(); + } + } + + + + +} + diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/req-capabilities-tab/requirement-list/requirement-list.component.html b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/req-capabilities-tab/requirement-list/requirement-list.component.html new file mode 100644 index 0000000000..8292729cf8 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/req-capabilities-tab/requirement-list/requirement-list.component.html @@ -0,0 +1,20 @@ +
+
+
+
+
{{requirement.name}} 
+
{{requirement.node}} +
+
+
+ {{getRelation(requirement).type}}
+ {{getRelation(requirement).requirementName}} +
+
+
+
+
+
+
+ \ No newline at end of file diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/req-capabilities-tab/requirement-list/requirement-list.component.ts b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/req-capabilities-tab/requirement-list/requirement-list.component.ts new file mode 100644 index 0000000000..e167c47dcc --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/req-capabilities-tab/requirement-list/requirement-list.component.ts @@ -0,0 +1,40 @@ +import { Component, Input } from '@angular/core'; +import { Component as TopologyTemplate, RelationshipModel, Relationship, Requirement } from "app/models"; +import { CompositionService } from "app/ng2/pages/composition/composition.service"; +import { ResourceNamePipe } from "app/ng2/pipes/resource-name.pipe"; + +@Component({ + selector: 'requirement-list', + templateUrl: './requirement-list.component.html' +}) +export class RequirementListComponent { + @Input() component: TopologyTemplate; + @Input() requirements: Array; + @Input() isInstanceSelected:boolean; + + + constructor(private compositionService: CompositionService) { } + + + public getRelation = (requirement:any):any => { + if (this.isInstanceSelected && this.component.componentInstancesRelations) { + let relationItem:Array = _.filter(this.component.componentInstancesRelations, (relation:RelationshipModel) => { + return relation.fromNode === this.component.uniqueId && + _.filter(relation.relationships, (relationship:Relationship) => { + return relationship.relation.requirement == requirement.name && relationship.relation.requirementOwnerId == requirement.ownerId; + }).length; + }); + + if (relationItem && relationItem.length) { + return { + type: requirement.relationship.split('.').pop(), + requirementName: ResourceNamePipe.getDisplayName(this.compositionService.componentInstances[_.map + (this.compositionService.componentInstances, "uniqueId").indexOf(relationItem[0].toNode)].name) + }; + } + } + return null; + }; + +}; + diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/service-consumption-tab/service-consumption-tab.component.html b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/service-consumption-tab/service-consumption-tab.component.html new file mode 100644 index 0000000000..a52c841156 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/service-consumption-tab/service-consumption-tab.component.html @@ -0,0 +1,15 @@ + +
{{input.title}}
+ + + + +
+ diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/service-consumption-tab/service-consumption-tab.component.less b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/service-consumption-tab/service-consumption-tab.component.less new file mode 100644 index 0000000000..e69de29bb2 diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/service-consumption-tab/service-consumption-tab.component.ts b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/service-consumption-tab/service-consumption-tab.component.ts new file mode 100644 index 0000000000..8715afd047 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/service-consumption-tab/service-consumption-tab.component.ts @@ -0,0 +1,89 @@ + +import { Component, Input } from '@angular/core'; +import { Store } from '@ngxs/store'; +import { + CapabilitiesGroup, + Capability, + Component as TopologyTemplate, + ComponentInstance, + FullComponentInstance, + InputBEModel, + InputsGroup, + InterfaceModel, + PropertiesGroup +} from 'app/models'; +import { ComponentMetadata } from '../../../../../../models/component-metadata'; +import { ServiceInstanceObject } from '../../../../../../models/service-instance-properties-and-interfaces'; +import { EventListenerService } from '../../../../../../services/event-listener-service'; +import { TopologyTemplateService } from '../../../../../services/component-services/topology-template.service'; +import { ComponentGenericResponse } from '../../../../../services/responses/component-generic-response'; +import { WorkspaceService } from '../../../../workspace/workspace.service'; +import { SelectedComponentType } from '../../../common/store/graph.actions'; +import { CompositionService } from '../../../composition.service'; + +@Component({ + selector: 'service-consumption-tab', + templateUrl: './service-consumption-tab.component.html', + styleUrls: ['./service-consumption-tab.component.less'], +}) +export class ServiceConsumptionTabComponent { + isComponentInstanceSelected: boolean; + + instancesMappedList: ServiceInstanceObject[]; + componentInstancesProperties: PropertiesGroup; + componentInstancesInputs: InputsGroup; + componentInstancesInterfaces: Map; + componentInputs: InputBEModel[]; + componentCapabilities: Capability[]; + instancesCapabilitiesMap: Map; + metadata: ComponentMetadata; + + @Input() isViewOnly: boolean; + @Input() componentType: SelectedComponentType; + @Input() component: TopologyTemplate | FullComponentInstance; + @Input() input: any; + + constructor(private store: Store, + private topologyTemplateService: TopologyTemplateService, + private workspaceService: WorkspaceService, + private compositionService: CompositionService, + private eventListenerService: EventListenerService ) {} + ngOnInit() { + this.metadata = this.workspaceService.metadata; + this.isComponentInstanceSelected = this.componentType === SelectedComponentType.COMPONENT_INSTANCE; + this.initInstances(); + } + + private initInstances = (): void => { + this.topologyTemplateService.getServiceConsumptionData(this.metadata.componentType, this.metadata.uniqueId).subscribe((genericResponse: ComponentGenericResponse) => { + this.componentInstancesProperties = genericResponse.componentInstancesProperties; + this.componentInstancesInputs = genericResponse.componentInstancesInputs; + this.componentInstancesInterfaces = genericResponse.componentInstancesInterfaces; + this.componentInputs = genericResponse.inputs; + this.buildInstancesCapabilitiesMap(genericResponse.componentInstances); + this.updateInstanceAttributes(); + }); + } + + private buildInstancesCapabilitiesMap = (componentInstances: Array): void => { + this.instancesCapabilitiesMap = new Map(); + let flattenCapabilities = []; + _.forEach(componentInstances, (componentInstance) => { + flattenCapabilities = CapabilitiesGroup.getFlattenedCapabilities(componentInstance.capabilities); + this.instancesCapabilitiesMap[componentInstance.uniqueId] = _.filter(flattenCapabilities, cap => cap.properties && cap.ownerId === componentInstance.uniqueId); + }); + } + + private updateInstanceAttributes = (): void => { + if (this.isComponentInstanceSelected && this.componentInstancesProperties) { + this.instancesMappedList = this.compositionService.componentInstances.map((coInstance) => new ServiceInstanceObject({ + id: coInstance.uniqueId, + name: coInstance.name, + properties: this.componentInstancesProperties[coInstance.uniqueId] || [], + inputs: this.componentInstancesInputs[coInstance.uniqueId] || [], + interfaces: this.componentInstancesInterfaces[coInstance.uniqueId] || [] + })); + } + } + +} diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/service-dependencies-tab/service-dependencies-tab.component.html b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/service-dependencies-tab/service-dependencies-tab.component.html new file mode 100644 index 0000000000..47351a46a1 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/service-dependencies-tab/service-dependencies-tab.component.html @@ -0,0 +1,18 @@ + +
{{input.title}}
+ +
+ + +
+
+
diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/service-dependencies-tab/service-dependencies-tab.component.less b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/service-dependencies-tab/service-dependencies-tab.component.less new file mode 100644 index 0000000000..47e26e2d64 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/service-dependencies-tab/service-dependencies-tab.component.less @@ -0,0 +1,3 @@ +:host /deep/ .expand-collapse-content { + padding: 0 0 10px; +} \ No newline at end of file diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/service-dependencies-tab/service-dependencies-tab.component.ts b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/service-dependencies-tab/service-dependencies-tab.component.ts new file mode 100644 index 0000000000..5171e3b607 --- /dev/null +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/service-dependencies-tab/service-dependencies-tab.component.ts @@ -0,0 +1,95 @@ + +import { Component, Input } from '@angular/core'; +import { Store } from '@ngxs/store'; +import { + CapabilitiesGroup, + Capability, + Component as TopologyTemplate, + ComponentInstance, + FullComponentInstance, + InputBEModel, + InputsGroup, + InterfaceModel, + PropertiesGroup, + PropertyBEModel, +} from 'app/models'; +import { DEPENDENCY_EVENTS } from 'app/utils/constants'; +import { ComponentMetadata } from '../../../../../../models/component-metadata'; +import { ServiceInstanceObject } from '../../../../../../models/service-instance-properties-and-interfaces'; +import { EventListenerService } from '../../../../../../services/event-listener-service'; +import { ConstraintObject } from '../../../../../components/logic/service-dependencies/service-dependencies.component'; +import { TopologyTemplateService } from '../../../../../services/component-services/topology-template.service'; +import { ComponentGenericResponse } from '../../../../../services/responses/component-generic-response'; +import { WorkspaceService } from '../../../../workspace/workspace.service'; +import { SelectedComponentType } from '../../../common/store/graph.actions'; +import { CompositionService } from '../../../composition.service'; + +@Component({ + selector: 'service-dependencies-tab', + templateUrl: 'service-dependencies-tab.component.html', + styleUrls: ['service-dependencies-tab.component.less'] +}) +export class ServiceDependenciesTabComponent { + isComponentInstanceSelected: boolean; + + selectedInstanceSiblings: ServiceInstanceObject[]; + componentInstancesConstraints: any[]; + selectedInstanceConstraints: ConstraintObject[]; + selectedInstanceProperties: PropertyBEModel[]; + componentInstanceProperties: PropertiesGroup; + metaData: ComponentMetadata; + + @Input() isViewOnly: boolean; + @Input() componentType: SelectedComponentType; + @Input() component: FullComponentInstance | TopologyTemplate; + @Input() input: any; + + constructor(private store: Store, + private topologyTemplateService: TopologyTemplateService, + private workspaceService: WorkspaceService, + private compositionService: CompositionService, + private eventListenerService: EventListenerService) { + } + + ngOnInit() { + this.metaData = this.workspaceService.metadata; + this.isComponentInstanceSelected = this.componentType === SelectedComponentType.COMPONENT_INSTANCE; + this.initInstancesWithProperties(); + this.loadConstraints(); + this.initInstancesWithProperties(); + } + + public loadConstraints = (): void => { + this.topologyTemplateService.getServiceFilterConstraints(this.metaData.componentType, this.metaData.uniqueId).subscribe((response) => { + this.componentInstancesConstraints = response.nodeFilterData; + }); + } + + public notifyDependencyEventsObserver = (isChecked: boolean): void => { + this.eventListenerService.notifyObservers(DEPENDENCY_EVENTS.ON_DEPENDENCY_CHANGE, isChecked); + } + + public updateSelectedInstanceConstraints = (constraintsList:Array):void => { + this.componentInstancesConstraints[this.component.uniqueId].properties = constraintsList; + this.selectedInstanceConstraints = this.componentInstancesConstraints[this.component.uniqueId].properties; + } + + private initInstancesWithProperties = (): void => { + this.topologyTemplateService.getComponentInstanceProperties(this.metaData.componentType, this.metaData.uniqueId).subscribe((genericResponse: ComponentGenericResponse) => { + this.componentInstanceProperties = genericResponse.componentInstancesProperties; + this.updateInstanceAttributes(); + }); + } + + private updateInstanceAttributes = (): void => { + if (this.isComponentInstanceSelected && this.componentInstanceProperties) { + const instancesMappedList = this.compositionService.componentInstances.map((coInstance) => new ServiceInstanceObject({ + id: coInstance.uniqueId, + name: coInstance.name, + properties: this.componentInstanceProperties[coInstance.uniqueId] || [] + })); + this.selectedInstanceProperties = this.componentInstanceProperties[this.component.uniqueId]; + this.selectedInstanceSiblings = instancesMappedList.filter((coInstance) => coInstance.id !== this.component.uniqueId); + } + } +} -- cgit 1.2.3-korg