summaryrefslogtreecommitdiffstats
path: root/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/artifacts-tab
diff options
context:
space:
mode:
Diffstat (limited to 'catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/artifacts-tab')
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/artifacts-tab/__snapshots__/artifact-tab.component.spec.ts.snap50
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/artifacts-tab/artifact-tab.component.spec.ts303
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/artifacts-tab/artifacts-tab.component.html119
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/artifacts-tab/artifacts-tab.component.less169
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/artifacts-tab/artifacts-tab.component.ts204
5 files changed, 845 insertions, 0 deletions
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`] = `
+<artifacts-tab
+ addOrUpdate={[Function Function]}
+ allowDeleteAndUpdateArtifact={[Function Function]}
+ artifactService={[Function Object]}
+ componentInstanceService="undefined"
+ compositionService={[Function Object]}
+ delete={[Function Function]}
+ getEnvArtifact={[Function Function]}
+ getTitle={[Function Function]}
+ heatToEnv={[Function Map]}
+ isLicenseArtifact={[Function Function]}
+ loadArtifacts={[Function Function]}
+ store={[Function Store]}
+ topologyTemplateService="undefined"
+ updateEnvParams={[Function Function]}
+ viewEnvParams={[Function Function]}
+ workspaceService="undefined"
+>
+ <div
+ class="w-sdc-designer-sidebar-tab-content artifacts"
+ >
+ <div
+ class="w-sdc-designer-sidebar-section"
+ >
+ <ng2-expand-collapse
+ state="0"
+ >
+ <header
+ sdc-tooltip=""
+ >
+
+ </header>
+ <content
+ class="artifacts-container"
+ >
+ <div
+ class="w-sdc-designer-sidebar-section-content"
+ >
+
+ </div>
+
+ </content>
+ </ng2-expand-collapse>
+ </div>
+ </div>
+</artifacts-tab>
+`;
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<ArtifactsTabComponent>;
+ let compositionMockService: Partial<CompositionService>;
+ const workspaceMockService: Partial<WorkspaceService>;
+ const componentInstanceMockService: Partial<ComponentInstanceServiceNg2>;
+ const topologyTemplateMockService: Partial<TopologyTemplateService>;
+ let artifactsServiceMockService: Partial<ArtifactsService>;
+ 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 @@
+<div class="w-sdc-designer-sidebar-tab-content artifacts">
+ <div class="w-sdc-designer-sidebar-section">
+ <ng2-expand-collapse state="0">
+ <header sdc-tooltip tooltip-text="{{title}}">{{title}}</header>
+ <content class="artifacts-container">
+ <div class="w-sdc-designer-sidebar-section-content">
+ <div class="i-sdc-designer-sidebar-section-content-item" *ngFor="let artifact of artifacts$ | async">
+ <div class="i-sdc-designer-sidebar-section-content-item-artifact"
+ *ngIf="(!isComponentInstanceSelected || artifact.esId) && 'HEAT_ENV' !== artifact.artifactType"
+ attr.data-tests-id="'artifact-item-' + artifact.artifactDisplayName">
+ <span *ngIf="artifact.heatParameters?.length"
+ class="i-sdc-designer-sidebar-section-content-item-file-link"></span>
+ <div class="i-sdc-designer-sidebar-section-content-item-artifact-details"
+ [class.heat]="artifact.isHEAT() && artifact.heatParameters?.length">
+ <div *ngIf="artifact.artifactName"
+ class="i-sdc-designer-sidebar-section-content-item-artifact-filename"
+ attr.data-tests-id="artifactName-{{artifact.artifactDisplayName}}"
+ sdc-tooltip tooltip-text="{{artifact.artifactName}}">{{artifact.artifactName}}
+ </div>
+ <div class="artifact-buttons-container upper-buttons">
+
+
+ <svg-icon
+ *ngIf="!isViewOnly && !artifact.isFromCsar && artifact.artifactName"
+ name="trash-o" clickable="true" size="medium" mode="info"
+ class="artifact-button" testId="delete_{{artifact.artifactDisplayName}}"
+ (click)="delete(artifact)"></svg-icon>
+
+ <!--Display env parameters edit button for Instance -->
+ <svg-icon
+ *ngIf="!isViewOnly && artifact.isHEAT() && isComponentInstanceSelected && artifact.heatParameters?.length"
+ name="indesign_status" clickable="true" size="medium" mode="info"
+ class="artifact-button"
+ testId="edit-parameters-of-{{artifact.artifactDisplayName}}"
+ (click)="updateEnvParams(artifact)"
+ tooltip="Edit ENV Params"
+ ></svg-icon>
+
+ <!--Display env parameters VIEW button for Instance -->
+ <svg-icon
+ *ngIf="isViewOnly && artifact.isHEAT() && isComponentInstanceSelected && artifact.heatParameters?.length"
+ name="inputs-o" clickable="true" size="medium" mode="info"
+ class="artifact-button"
+ testId="view-parameters-of-{{artifact.artifactDisplayName}}"
+ (click)="viewEnvParams(artifact)"
+ tooltip="View ENV Params"
+ ></svg-icon>
+
+ <!--Display env parameters edit button for VF -->
+ <svg-icon
+ *ngIf = "!isViewOnly && !isComponentInstanceSelected && artifact.heatParameters?.length"
+ name="indesign_status" clickable="true" size="medium" mode="info"
+ class="artifact-button"
+ testId="edit-parameters-of-{{artifact.artifactDisplayName}}"
+ (click)="updateEnvParams(artifact)"></svg-icon>
+
+
+ <download-artifact *ngIf="artifact.esId && 'deployment' != type"
+ class="artifact-button"
+ [artifact]="artifact" [componentType]="component.componentType"
+ [componentId]="component.uniqueId"
+ testId="download_{{artifact.artifactDisplayName}}"
+ [isInstance]="isComponentInstanceSelected"></download-artifact>
+ <download-artifact *ngIf="artifact.esId && 'deployment' == type"
+ class="artifact-button"
+ [artifact]="artifact" [componentType]="component.componentType"
+ [componentId]="component.uniqueId"
+ [isInstance]="isComponentInstanceSelected"
+ testId="download_{{artifact.artifactDisplayName}}"
+ [showLoader]="artifact.isHEAT()"></download-artifact>
+
+ <button *ngIf="!isViewOnly && !artifact.esId && type==='deployment' && !isComponentInstanceSelected && !artifact.isThirdParty()"
+ class="artifact-button attach sprite e-sdc-small-icon-upload"
+ (click)="addOrUpdate(artifact)" type="button"
+ attr.data-tests-id="add_Artifact"></button>
+ </div>
+ <div>
+ <span class="i-sdc-designer-sidebar-section-content-item-artifact-details-name"
+ attr.data-tests-id="artifact_Display_Name-{{artifact.artifactDisplayName}}"
+ [ngClass]="{'hand enabled': artifact.allowDeleteAndUpdate}"
+ (click)="artifact.allowDeleteAndUpdate && addOrUpdate(artifact)"
+ sdc-tooltip tooltip-text="{{artifact.artifactDisplayName}}">{{artifact.artifactDisplayName}}</span>
+ <div class="i-sdc-designer-sidebar-section-content-item-artifact-heat-env"
+ *ngIf="artifact.heatParameters?.length">
+ <span attr.data-tests-id="heat_env_{{artifact.artifactDisplayName}}">{{artifact.artifactDisplayName}} (ENV)</span>
+ <div class="artifact-buttons-container">
+ <svg-icon *ngIf="!isViewOnly && envArtifactOf(artifact)"
+ name="edit-o" clickable="true" size="medium"
+ mode="info" class="artifact-button edit-pencil"
+ testId="edit_{{artifact.artifactDisplayName}}"
+ (click)="addOrUpdate(envArtifactOf(artifact))"></svg-icon>
+
+ <download-artifact [artifact]="envArtifactOf(artifact)"
+ class="artifact-button"
+ [componentType]="component.componentType"
+ [componentId]="component.uniqueId"
+ [isInstance]="isComponentInstanceSelected"
+ testId="download_env_{{artifact.artifactDisplayName}}"></download-artifact>
+ </div>
+ </div>
+ </div>
+
+ <div class="i-sdc-designer-sidebar-section-content-item-artifact-details-desc">
+ <span class="i-sdc-designer-sidebar-section-content-item-artifact-details-desc-label"
+ *ngIf="artifact.description">Description:</span>{{artifact.description}}
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="w-sdc-designer-sidebar-section-footer"
+ *ngIf="!isViewOnly && type!=='api' && (!isComponentInstanceSelected || isVfOrPnf() && (type !== 'deployment') || isComplex)">
+ <sdc-button testId="add_Artifact_Button" size="large" type="primary" text="Add Artifact"
+ (click)="addOrUpdate({})"></sdc-button>
+ </div>
+ </content>
+ </ng2-expand-collapse>
+ </div>
+</div>
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<ArtifactModel[]>;
+ private topologyTemplateType: string;
+ private topologyTemplateId: string;
+ private heatToEnv: Map<string, ArtifactModel>;
+ 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;
+ }
+}