aboutsummaryrefslogtreecommitdiffstats
path: root/catalog-ui/src/app/ng2/pages/composition/graph/canvas-zone
diff options
context:
space:
mode:
Diffstat (limited to 'catalog-ui/src/app/ng2/pages/composition/graph/canvas-zone')
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/graph/canvas-zone/__snapshots__/zone-container.component.spec.ts.snap35
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/graph/canvas-zone/zone-container.component.html30
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/graph/canvas-zone/zone-container.component.less62
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/graph/canvas-zone/zone-container.component.spec.ts46
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/graph/canvas-zone/zone-container.component.ts35
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/graph/canvas-zone/zone-instance/zone-instance.component.html27
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/graph/canvas-zone/zone-instance/zone-instance.component.less135
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/graph/canvas-zone/zone-instance/zone-instance.component.spec.ts132
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/graph/canvas-zone/zone-instance/zone-instance.component.ts128
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/graph/canvas-zone/zones-module.ts15
10 files changed, 645 insertions, 0 deletions
diff --git a/catalog-ui/src/app/ng2/pages/composition/graph/canvas-zone/__snapshots__/zone-container.component.spec.ts.snap b/catalog-ui/src/app/ng2/pages/composition/graph/canvas-zone/__snapshots__/zone-container.component.spec.ts.snap
new file mode 100644
index 0000000000..d4e2a7a359
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/graph/canvas-zone/__snapshots__/zone-container.component.spec.ts.snap
@@ -0,0 +1,35 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`ZoneContainerComponent should match current snapshot of palette element component 1`] = `
+<zone-container
+ backgroundClick={[Function EventEmitter]}
+ backgroundClicked={[Function Function]}
+ minimize={[Function EventEmitter]}
+ unminifyZone={[Function Function]}
+>
+ <div>
+ <div
+ class="sdc-canvas-zone__header"
+ >
+ <div
+ class="sdc-canvas-zone__title"
+ >
+
+ <span
+ class="sdc-canvas-zone__counter"
+ >
+
+ </span>
+ </div>
+ <span
+ class="sdc-canvas-zone__state-button"
+ >
+ –
+ </span>
+ </div>
+ <div
+ class="sdc-canvas-zone__container"
+ />
+ </div>
+</zone-container>
+`;
diff --git a/catalog-ui/src/app/ng2/pages/composition/graph/canvas-zone/zone-container.component.html b/catalog-ui/src/app/ng2/pages/composition/graph/canvas-zone/zone-container.component.html
new file mode 100644
index 0000000000..d6343a4a4f
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/graph/canvas-zone/zone-container.component.html
@@ -0,0 +1,30 @@
+<!--
+ ~ Copyright (C) 2018 AT&T Intellectual Property. All rights reserved.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+
+<div class="sdc-canvas-zone {{class}}-zone" [class.minimized]="minimized" [class.hidden]="!visible"
+ (click)="backgroundClicked()">
+ <div class="sdc-canvas-zone__header" (click)="unminifyZone(); $event.stopPropagation();">
+ <div class="sdc-canvas-zone__title">{{title}}
+ <span class="sdc-canvas-zone__counter">{{count}}</span>
+ </div>
+ <span class="sdc-canvas-zone__state-button">&ndash;</span>
+ </div>
+ <div class="sdc-canvas-zone__container" #scrollDiv>
+ <ng-content></ng-content>
+ </div>
+</div>
+
diff --git a/catalog-ui/src/app/ng2/pages/composition/graph/canvas-zone/zone-container.component.less b/catalog-ui/src/app/ng2/pages/composition/graph/canvas-zone/zone-container.component.less
new file mode 100644
index 0000000000..827786cc49
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/graph/canvas-zone/zone-container.component.less
@@ -0,0 +1,62 @@
+.sdc-canvas-zone {
+ width: 285px;
+ max-height:186px;
+ display:flex;
+ flex-direction:column;
+ color:white;
+ font-family:OpenSans-Regular, sans-serif;
+ transition: width .2s ease-in-out, max-height .2s ease-in-out .1s;
+ position:relative;
+ bottom:0px;
+ margin-right: 5px;
+
+ .sdc-canvas-zone__header {
+ background: #5A5A5A;
+ border-radius: 2px 2px 0 0;
+ padding: 5px 10px;
+ display:flex;
+ justify-content: space-between;
+ font-size: 14px;
+ text-transform:uppercase;
+ .sdc-canvas-zone__state-button {
+ font-weight:bold;
+ cursor:pointer;
+ }
+ }
+
+ .sdc-canvas-zone__container {
+ padding:5px;
+ background-color: #5A5A5A;
+ opacity:0.9;
+ flex: 1;
+ display:flex;
+ flex-direction: row;
+ align-items: flex-start;
+ flex-wrap:wrap;
+ overflow-y:auto;
+ min-height: 80px;
+ max-height: 170px;
+ }
+
+
+ &.minimized {
+ max-height:30px;
+ width:120px;
+ cursor:pointer;
+
+ .sdc-canvas-zone__state-button {
+ display:none;
+ }
+ .sdc-canvas-zone__container {
+ flex: 0 0 0;
+ min-height: 0;
+ padding: 0;
+ overflow-y:hidden;
+ transition: min-height .2s ease-in-out .2s;
+ transition: padding .1s ease-in-out 0s;
+ }
+ }
+ &.hidden {
+ display:none;
+ }
+} \ No newline at end of file
diff --git a/catalog-ui/src/app/ng2/pages/composition/graph/canvas-zone/zone-container.component.spec.ts b/catalog-ui/src/app/ng2/pages/composition/graph/canvas-zone/zone-container.component.spec.ts
new file mode 100644
index 0000000000..c432054492
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/graph/canvas-zone/zone-container.component.spec.ts
@@ -0,0 +1,46 @@
+import {async, ComponentFixture} from '@angular/core/testing';
+import {By} from '@angular/platform-browser';
+import {ConfigureFn, configureTests} from '../../../../../../jest/test-config.helper';
+import 'jest-dom/extend-expect';
+import {ZoneInstanceType} from '../../../../../../app/models/graph/zones/zone-instance';
+import {ZoneContainerComponent} from './zone-container.component';
+
+
+describe('ZoneContainerComponent', () => {
+ let fixture: ComponentFixture<ZoneContainerComponent>;
+
+ beforeEach(
+ async(() => {
+ const configure: ConfigureFn = testBed => {
+ testBed.configureTestingModule({
+ declarations: [ZoneContainerComponent]
+ });
+ };
+
+ configureTests(configure).then(testBed => {
+ fixture = testBed.createComponent(ZoneContainerComponent);
+ });
+ })
+ );
+
+
+ it('should match current snapshot of palette element component', () => {
+ expect(fixture).toMatchSnapshot();
+ });
+
+ it('should have a group-zone class when the ZoneInstanceType is GROUP',
+ () => {
+ fixture.componentInstance.type = ZoneInstanceType.GROUP;
+ fixture.detectChanges();
+ const compiled = fixture.debugElement.query(By.css('.sdc-canvas-zone'));
+ expect(compiled.nativeElement).toHaveClass('group-zone');
+ });
+
+ it('should have a policy-zone class when the ZoneInstanceType is POLICY',
+ () => {
+ fixture.componentInstance.type = ZoneInstanceType.POLICY;
+ fixture.detectChanges();
+ const compiled = fixture.debugElement.query(By.css('.sdc-canvas-zone'));
+ expect(compiled.nativeElement).toHaveClass('policy-zone');
+ });
+}); \ No newline at end of file
diff --git a/catalog-ui/src/app/ng2/pages/composition/graph/canvas-zone/zone-container.component.ts b/catalog-ui/src/app/ng2/pages/composition/graph/canvas-zone/zone-container.component.ts
new file mode 100644
index 0000000000..4757c1f36d
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/graph/canvas-zone/zone-container.component.ts
@@ -0,0 +1,35 @@
+import { Component, Input, Output, ViewEncapsulation, EventEmitter, OnInit } from '@angular/core';
+import { ZoneInstanceType } from 'app/models/graph/zones/zone-instance';
+
+@Component({
+ selector: 'zone-container',
+ templateUrl: './zone-container.component.html',
+ styleUrls: ['./zone-container.component.less'],
+ encapsulation: ViewEncapsulation.None
+})
+
+export class ZoneContainerComponent implements OnInit {
+ @Input() title:string;
+ @Input() type:ZoneInstanceType;
+ @Input() count:number;
+ @Input() visible:boolean;
+ @Input() minimized:boolean;
+ @Output() minimize: EventEmitter<any> = new EventEmitter<any>();
+ @Output() backgroundClick: EventEmitter<void> = new EventEmitter<void>();
+ private class:string;
+
+ constructor() {}
+
+ ngOnInit() {
+ this.class = ZoneInstanceType[this.type].toLowerCase();
+ }
+
+ private unminifyZone = () => {
+ this.minimize.emit();
+ }
+
+ private backgroundClicked = () => {
+ this.backgroundClick.emit();
+ }
+
+} \ No newline at end of file
diff --git a/catalog-ui/src/app/ng2/pages/composition/graph/canvas-zone/zone-instance/zone-instance.component.html b/catalog-ui/src/app/ng2/pages/composition/graph/canvas-zone/zone-instance/zone-instance.component.html
new file mode 100644
index 0000000000..d97be69e34
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/graph/canvas-zone/zone-instance/zone-instance.component.html
@@ -0,0 +1,27 @@
+<!--
+ ~ Copyright (C) 2018 AT&T Intellectual Property. All rights reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+
+<div #currentComponent class="zone-instance mode-{{zoneInstance.mode}}" [class.locked]="activeInstanceMode > MODE.HOVER"
+ [class.hiding]="hidden"
+ (mouseenter)="setMode(MODE.HOVER)" (mouseleave)="setMode(MODE.NONE)" (click)="setMode(MODE.SELECTED, $event)">
+ <div class="zone-instance__body" sdc-tooltip tooltip-text="{{zoneInstance.instanceData.name}}" [attr.data-tests-id]="zoneInstance.instanceData.name">
+ <div *ngIf="zoneInstance.handle" class="target-handle {{zoneInstance.handle}}"
+ (click)="tagHandleClicked($event)"></div>
+ <div *ngIf="!isViewOnly" class="zone-instance__handle" (click)="setMode(MODE.TAG, $event)">+</div>
+ <div class="zone-instance__body-content">{{zoneInstance.assignments.length || defaultIconText}}</div>
+ </div>
+ <div class="zone-instance__name">{{zoneInstance.instanceData.name}}</div>
+</div>
diff --git a/catalog-ui/src/app/ng2/pages/composition/graph/canvas-zone/zone-instance/zone-instance.component.less b/catalog-ui/src/app/ng2/pages/composition/graph/canvas-zone/zone-instance/zone-instance.component.less
new file mode 100644
index 0000000000..c34b8e149a
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/graph/canvas-zone/zone-instance/zone-instance.component.less
@@ -0,0 +1,135 @@
+@import '../../../../../../../assets/styles/variables';
+
+.zone-instance {
+
+ width:76px;
+ margin:5px;
+ opacity:1;
+
+ .zone-instance__handle {
+ display:none;
+ position:absolute;
+ left: 31px;
+ top: 8px;
+ width:22px;
+ height:22px;
+ cursor:pointer;
+ border: solid @main_color_p 1px;
+ border-radius: 2px;
+ text-align: center;
+ font-weight:bold;
+ }
+
+ .zone-instance__body {
+ position:relative;
+ margin:0 auto;
+ width:43px;
+ height:43px;
+ display:flex;
+ padding:3px;
+ }
+
+ .zone-instance__body-content {
+ border-radius: 2px;
+ flex:1;
+ color:@main_color_p;
+ font-size:16px;
+ text-align:center;
+ display:flex;
+ align-items: center;
+ justify-content: center;
+ box-shadow:none;
+ transition:box-shadow 5s;
+ }
+
+ .zone-instance__name {
+ text-overflow: ellipsis;
+ overflow: hidden;
+ white-space: nowrap;
+ text-align:center;
+ }
+ /* Dynamic classes below */
+
+ .target-handle {
+ position:absolute;
+ width:18px;
+ height:18px;
+ display:block;
+ top: -4px;
+ right: -6px;
+ background-size: 100% 100%;
+ cursor: url("../../../../../../../assets/styles/images/canvas-tagging-icons/policy_2.svg"), pointer;
+
+ &.tagged-policy {
+ background-image: url('../../../../../../../assets/styles/images/canvas-tagging-icons/policy_added.svg');
+ }
+
+ &.tag-available {
+ background-image: url('../../../../../../../assets/styles/images/canvas-tagging-icons/indication.svg');
+ }
+ }
+
+
+ &.mode-1, &.mode-2, &.mode-3 { //hover, selected, tag
+ .zone-instance__body {
+ border:solid 2px;
+ border-radius: 2px;
+ padding:2px;
+ cursor:pointer;
+ }
+ }
+
+ &.mode-1, &.mode-2:hover{
+ .zone-instance__handle{
+ display:block;
+ }
+ }
+
+ &.locked {
+ cursor: inherit;
+ }
+
+ &.hiding {
+ opacity:0;
+ .zone-instance__body-content {
+ box-shadow: #CCC 0px 0px 15px;
+ }
+ }
+
+
+ &.mode-3 .zone-instance__handle {
+ width:24px;
+ height:24px;
+ right:-6px;
+ top:7px;
+ display:block;
+ background-image: linear-gradient(-140deg, #009E98 0%, #97D648 100%);
+ border: 2px solid @main_color_p;
+ border-radius: 2px;
+ box-shadow: inset 2px -2px 3px 0 #007A3E;
+ }
+
+}
+.sdc-canvas-zone.group-zone {
+ .zone-instance__handle {
+ background-color:@main_color_a;
+ }
+ .zone-instance__body {
+ border-color:@main_color_a;
+ .zone-instance__body-content {
+ background: @main_color_a;
+ }
+ }
+}
+
+.sdc-canvas-zone.policy-zone {
+ .zone-instance__handle {
+ background-color:@main_color_r;
+ }
+ .zone-instance__body {
+ border-color:@main_color_r;
+ .zone-instance__body-content {
+ background: @main_color_r;
+ }
+ }
+} \ No newline at end of file
diff --git a/catalog-ui/src/app/ng2/pages/composition/graph/canvas-zone/zone-instance/zone-instance.component.spec.ts b/catalog-ui/src/app/ng2/pages/composition/graph/canvas-zone/zone-instance/zone-instance.component.spec.ts
new file mode 100644
index 0000000000..f5a5f6f546
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/graph/canvas-zone/zone-instance/zone-instance.component.spec.ts
@@ -0,0 +1,132 @@
+import { ComponentFixture, TestBed, async } from '@angular/core/testing';
+import { NO_ERRORS_SCHEMA } from '@angular/core';
+import { SimpleChanges } from '@angular/core';
+import { PoliciesService } from 'app/ng2/services/policies.service';
+import { GroupsService } from 'app/ng2/services/groups.service';
+import { EventListenerService } from 'app/services';
+import { Store } from '@ngxs/store';
+import { CompositionService } from 'app/ng2/pages/composition/composition.service';
+import { ZoneInstanceComponent } from './zone-instance.component';
+import { ZoneInstanceType, ZoneInstance, ZoneInstanceMode, ZoneInstanceAssignmentType, IZoneInstanceAssignment } from "app/models";
+import { PolicyInstance } from "app/models/graph/zones/policy-instance";
+import { Subject, of } from 'rxjs';
+import { _throw } from 'rxjs/observable/throw';
+
+describe('ZoneInstanceComponent', () => {
+ let component: ZoneInstanceComponent;
+ let fixture: ComponentFixture<ZoneInstanceComponent>;
+
+ let createPolicyInstance = () => {
+ let policy = new PolicyInstance();
+ policy.targets = {COMPONENT_INSTANCES: [], GROUPS: []};
+ return new ZoneInstance(policy, '', '');
+ }
+
+ beforeEach(() => {
+ const policiesServiceStub = {updateZoneInstanceAssignments : jest.fn()};
+ const groupsServiceStub = {};
+ const eventListenerServiceStub = {};
+ const storeStub = {};
+ const compositionServiceStub = {};
+ TestBed.configureTestingModule({
+ schemas: [NO_ERRORS_SCHEMA],
+ declarations: [ZoneInstanceComponent],
+ providers: [
+ { provide: PoliciesService, useValue: policiesServiceStub },
+ { provide: GroupsService, useValue: groupsServiceStub },
+ { provide: EventListenerService, useValue: eventListenerServiceStub },
+ { provide: Store, useValue: storeStub },
+ { provide: CompositionService, useValue: compositionServiceStub }
+ ]
+ }).compileComponents().then(() => {
+ fixture = TestBed.createComponent(ZoneInstanceComponent);
+ component = fixture.componentInstance;
+ });
+ });
+
+ it('can load instance', async((done) => {
+ component.zoneInstance = <ZoneInstance>{type : ZoneInstanceType.POLICY, instanceData: {name: 'test policy'}, assignments: []};
+ component.forceSave = new Subject<Function>();
+ fixture.detectChanges();
+ expect(component).toBeTruthy();
+ }));
+
+
+ it('if another instance is already tagging, i cannot change my mode', ()=> {
+ component.zoneInstance = <ZoneInstance>{ mode: ZoneInstanceMode.NONE };
+ component.isActive = false;
+ component.activeInstanceMode = ZoneInstanceMode.TAG;
+ component.setMode(ZoneInstanceMode.SELECTED);
+ expect(component.zoneInstance.mode).toBe(ZoneInstanceMode.NONE);
+ });
+
+ it('if i am active(selected) and NOT in tag mode, I can set another mode', ()=> {
+ component.isActive = true;
+ component.zoneInstance = <ZoneInstance>{ mode: ZoneInstanceMode.SELECTED };
+ jest.spyOn(component.modeChange, 'emit');
+ component.setMode(ZoneInstanceMode.NONE);
+ expect(component.modeChange.emit).toHaveBeenCalledWith({instance: component.zoneInstance, newMode: ZoneInstanceMode.NONE });
+ });
+
+ it('if i am active and in tag mode and i try to set mode other than tag, I am not allowed', ()=> {
+ component.isActive = true;
+ component.zoneInstance = <ZoneInstance>{ mode: ZoneInstanceMode.TAG };
+ component.setMode(ZoneInstanceMode.SELECTED);
+ expect(component.zoneInstance.mode).toBe(ZoneInstanceMode.TAG);
+ });
+
+ it('if i am active and in tag mode and click tag again and no changes, does NOT call save, but DOES turn tagging off', ()=> {
+ component.isActive = true;
+ component.zoneInstance = createPolicyInstance();
+ component.zoneService = component.policiesService;
+ component.zoneInstance.mode = ZoneInstanceMode.TAG;
+ jest.spyOn(component.zoneService, 'updateZoneInstanceAssignments');
+ jest.spyOn(component.modeChange, 'emit');
+
+ component.setMode(ZoneInstanceMode.TAG);
+
+ expect(component.zoneService.updateZoneInstanceAssignments).not.toHaveBeenCalled();
+ expect(component.modeChange.emit).toHaveBeenCalledWith({instance: component.zoneInstance, newMode: ZoneInstanceMode.NONE });
+
+ });
+ it('if i am active and in tag mode and click tag again and HAVE changes, calls save AND turns tagging off', ()=> {
+ component.isActive = true;
+ component.zoneInstance = createPolicyInstance();
+ component.zoneService = component.policiesService;
+ component.zoneInstance.mode = ZoneInstanceMode.TAG;
+ component.zoneInstance.assignments.push(<IZoneInstanceAssignment>{uniqueId: '123', type: ZoneInstanceAssignmentType.COMPONENT_INSTANCES});
+ jest.spyOn(component.zoneService, 'updateZoneInstanceAssignments').mockReturnValue(of(true));
+ jest.spyOn(component.modeChange, 'emit');
+
+ component.setMode(ZoneInstanceMode.TAG);
+
+ expect(component.zoneService.updateZoneInstanceAssignments).toHaveBeenCalled();
+ expect(component.modeChange.emit).toHaveBeenCalledWith({instance: component.zoneInstance, newMode: ZoneInstanceMode.NONE });
+ });
+
+ it('on save error, temporary assignment list is reverted to saved assignments', ()=> {
+ component.isActive = true;
+ component.zoneInstance = createPolicyInstance();
+ component.zoneService = component.policiesService;
+ component.zoneInstance.mode = ZoneInstanceMode.TAG;
+ component.zoneInstance.assignments.push(<IZoneInstanceAssignment>{uniqueId: '123', type: ZoneInstanceAssignmentType.COMPONENT_INSTANCES});
+ jest.spyOn(component.zoneService, 'updateZoneInstanceAssignments').mockReturnValue(_throw({status: 404}));
+
+ component.setMode(ZoneInstanceMode.TAG);
+
+ expect(component.zoneInstance.assignments.length).toEqual(0);
+ });
+
+ it('on save success, all changes are saved to zoneInstance.savedAssignments', ()=> {
+ component.isActive = true;
+ component.zoneInstance = createPolicyInstance();
+ component.zoneService = component.policiesService;
+ component.zoneInstance.mode = ZoneInstanceMode.TAG;
+ component.zoneInstance.assignments.push(<IZoneInstanceAssignment>{uniqueId: '123', type: ZoneInstanceAssignmentType.COMPONENT_INSTANCES});
+ jest.spyOn(component.zoneService, 'updateZoneInstanceAssignments').mockReturnValue(of(true));
+
+ component.setMode(ZoneInstanceMode.TAG);
+
+ expect(component.zoneInstance.instanceData.getSavedAssignments().length).toEqual(1);
+ });
+});
diff --git a/catalog-ui/src/app/ng2/pages/composition/graph/canvas-zone/zone-instance/zone-instance.component.ts b/catalog-ui/src/app/ng2/pages/composition/graph/canvas-zone/zone-instance/zone-instance.component.ts
new file mode 100644
index 0000000000..1b1363e576
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/graph/canvas-zone/zone-instance/zone-instance.component.ts
@@ -0,0 +1,128 @@
+import { Component, Input, Output, EventEmitter, ViewEncapsulation, OnInit, SimpleChange, ElementRef, ViewChild, SimpleChanges } from '@angular/core';
+import {
+ ZoneInstance, ZoneInstanceMode, ZoneInstanceType,
+ IZoneInstanceAssignment
+} from 'app/models/graph/zones/zone-instance';
+import { PoliciesService } from 'app/ng2/services/policies.service';
+import { GroupsService } from 'app/ng2/services/groups.service';
+import { IZoneService } from "app/models/graph/zones/zone";
+import { EventListenerService } from 'app/services';
+import { GRAPH_EVENTS } from 'app/utils';
+import { Subject } from 'rxjs';
+import { Store } from "@ngxs/store";
+import { CompositionService } from "app/ng2/pages/composition/composition.service";
+import { PolicyInstance } from "app/models";
+import {SelectedComponentType, SetSelectedComponentAction} from "../../../common/store/graph.actions";
+
+
+@Component({
+ selector: 'zone-instance',
+ templateUrl: './zone-instance.component.html',
+ styleUrls: ['./zone-instance.component.less'],
+ encapsulation: ViewEncapsulation.None
+})
+export class ZoneInstanceComponent implements OnInit {
+
+ @Input() zoneInstance:ZoneInstance;
+ @Input() defaultIconText:string;
+ @Input() isActive:boolean;
+ @Input() isViewOnly:boolean;
+ @Input() activeInstanceMode: ZoneInstanceMode;
+ @Input() hidden:boolean;
+ @Input() forceSave:Subject<Function>;
+ @Output() modeChange: EventEmitter<any> = new EventEmitter<any>();
+ @Output() assignmentSaveStart: EventEmitter<void> = new EventEmitter<void>();
+ @Output() assignmentSaveComplete: EventEmitter<boolean> = new EventEmitter<boolean>();
+ @Output() tagHandleClick: EventEmitter<ZoneInstance> = new EventEmitter<ZoneInstance>();
+ @ViewChild('currentComponent') currentComponent: ElementRef;
+ private MODE = ZoneInstanceMode;
+ private zoneService:IZoneService;
+
+ constructor(private policiesService:PoliciesService, private groupsService:GroupsService, private eventListenerService:EventListenerService, private compositionService:CompositionService, private store:Store){}
+
+ ngOnInit(){
+ if(this.zoneInstance.type == ZoneInstanceType.POLICY){
+ this.zoneService = this.policiesService;
+ } else {
+ this.zoneService = this.groupsService;
+ }
+ if(this.forceSave) {
+ this.forceSave.subscribe((afterSaveFunction:Function) => {
+ this.setMode(ZoneInstanceMode.TAG, null, afterSaveFunction);
+ })
+ }
+ }
+
+ ngOnChanges(changes:SimpleChanges) {
+ if(changes.hidden){
+ this.currentComponent.nativeElement.scrollIntoView({behavior: "smooth", block: "nearest", inline:"end"});
+ }
+ }
+
+ ngOnDestroy() {
+ if(this.forceSave) {
+ this.forceSave.unsubscribe();
+ }
+ }
+
+ private setMode = (mode:ZoneInstanceMode, event?:any, afterSaveCallback?:Function):void => {
+
+ if(event){ //prevent event from handle and then repeat event from zone instance
+ event.stopPropagation();
+ }
+
+ if(!this.isActive && this.activeInstanceMode === ZoneInstanceMode.TAG) {
+ return; //someone else is tagging. No events allowed
+ }
+
+ if(this.isActive && this.zoneInstance.mode === ZoneInstanceMode.TAG){
+ if(mode !== ZoneInstanceMode.TAG) {
+ return; //ignore all other events. The only valid option is saving changes.
+ }
+
+ let oldAssignments:Array<IZoneInstanceAssignment> = this.zoneInstance.instanceData.getSavedAssignments();
+ if(this.zoneInstance.isZoneAssignmentChanged(oldAssignments, this.zoneInstance.assignments)) {
+
+ this.assignmentSaveStart.emit();
+
+ this.zoneService.updateZoneInstanceAssignments(this.zoneInstance.parentComponentType, this.zoneInstance.parentComponentID, this.zoneInstance.instanceData.uniqueId, this.zoneInstance.assignments).subscribe(
+ (success) => {
+ this.zoneInstance.instanceData.setSavedAssignments(this.zoneInstance.assignments);
+
+ if(this.zoneInstance.instanceData instanceof PolicyInstance){
+ this.compositionService.updatePolicy(this.zoneInstance.instanceData);
+ this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_POLICY_INSTANCE_UPDATE, this.zoneInstance.instanceData);
+ this.store.dispatch(new SetSelectedComponentAction({component: this.zoneInstance.instanceData, type: SelectedComponentType.POLICY}));
+ } else {
+ this.compositionService.updateGroup(this.zoneInstance.instanceData);
+ this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_GROUP_INSTANCE_UPDATE, this.zoneInstance.instanceData);
+ this.store.dispatch(new SetSelectedComponentAction({component: this.zoneInstance.instanceData, type: SelectedComponentType.GROUP}));
+ }
+
+ this.assignmentSaveComplete.emit(true);
+ if(afterSaveCallback) afterSaveCallback();
+ }, (error) => {
+ this.zoneInstance.assignments = oldAssignments;
+ this.assignmentSaveComplete.emit(false);
+ });
+ } else {
+ if(afterSaveCallback) afterSaveCallback();
+ }
+ this.modeChange.emit({newMode: ZoneInstanceMode.NONE, instance: this.zoneInstance});
+ // this.store.dispatch(new unsavedChangesActions.RemoveUnsavedChange(this.zoneInstance.instanceData.uniqueId));
+
+
+ } else {
+ this.modeChange.emit({newMode: mode, instance: this.zoneInstance});
+ if(mode == ZoneInstanceMode.TAG){
+ // this.store.dispatch(new unsavedChangesActions.AddUnsavedChange(this.zoneInstance.instanceData.uniqueId));
+ }
+ }
+ }
+
+ private tagHandleClicked = (event:Event) => {
+ this.tagHandleClick.emit(this.zoneInstance);
+ event.stopPropagation();
+ };
+
+} \ No newline at end of file
diff --git a/catalog-ui/src/app/ng2/pages/composition/graph/canvas-zone/zones-module.ts b/catalog-ui/src/app/ng2/pages/composition/graph/canvas-zone/zones-module.ts
new file mode 100644
index 0000000000..3287c01f5a
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/graph/canvas-zone/zones-module.ts
@@ -0,0 +1,15 @@
+import { NgModule } from "@angular/core";
+import { CommonModule } from "@angular/common";
+import { ZoneContainerComponent } from "./zone-container.component";
+import { ZoneInstanceComponent } from "./zone-instance/zone-instance.component";
+import { SdcUiComponentsModule } from "onap-ui-angular";
+
+@NgModule({
+ declarations: [ZoneContainerComponent, ZoneInstanceComponent],
+ imports: [CommonModule, SdcUiComponentsModule],
+ entryComponents: [ZoneContainerComponent, ZoneInstanceComponent],
+ exports: [ZoneContainerComponent, ZoneInstanceComponent],
+ providers: []
+})
+export class ZoneModules {
+} \ No newline at end of file