summaryrefslogtreecommitdiffstats
path: root/catalog-ui/src/app/ng2/pages
diff options
context:
space:
mode:
authorMichael Lando <ml636r@att.com>2018-07-29 16:13:45 +0300
committerMichael Lando <ml636r@att.com>2018-07-29 16:20:34 +0300
commit5b593496b8f1b8e8be8d7d2dbcc223332e65a49b (patch)
tree2f9dfc45191e723da69cf74be7829784e9741b94 /catalog-ui/src/app/ng2/pages
parent9200382f2ce7b4bb729aa287d0878004b2d2b4f9 (diff)
re base code
Change-Id: I12a5ca14a6d8a87e9316b9ff362eb131105f98a5 Issue-ID: SDC-1566 Signed-off-by: Michael Lando <ml636r@att.com>
Diffstat (limited to 'catalog-ui/src/app/ng2/pages')
-rw-r--r--catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-models/ui-component-to-upgrade.ts103
-rw-r--r--catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-status/automated-upgrade-status.component.html10
-rw-r--r--catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-status/automated-upgrade-status.component.ts24
-rw-r--r--catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/list-item-inner-content/list-item-inner-content.component.html25
-rw-r--r--catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/list-item-inner-content/list-item-inner-content.component.less25
-rw-r--r--catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/list-item-inner-content/list-item-inner-content.component.ts24
-rw-r--r--catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/list-item-order-pipe/list-item-order-pipe.ts42
-rw-r--r--catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/upgrade-line-item/upgrade-line-item.component.html6
-rw-r--r--catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/upgrade-line-item/upgrade-line-item.component.less17
-rw-r--r--catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/upgrade-line-item/upgrade-line-item.component.ts19
-rw-r--r--catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/upgrade-list-item-status/upgrade-list-status-item.component.html13
-rw-r--r--catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/upgrade-list-item-status/upgrade-list-status-item.component.ts19
-rw-r--r--catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/upgrade-list-item.component.less44
-rw-r--r--catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/upgrade-list-item/upgrade-list-item.component.html19
-rw-r--r--catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/upgrade-list-item/upgrade-list-item.component.ts23
-rw-r--r--catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade.component.html25
-rw-r--r--catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade.component.less23
-rw-r--r--catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade.component.ts65
-rw-r--r--catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade.module.ts34
-rw-r--r--catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade.service.ts279
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/panel/panel-header/panel-header.component.html14
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/panel/panel-header/panel-header.component.less34
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/panel/panel-header/panel-header.component.ts135
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/panel/panel-header/panel-header.module.ts51
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/base/base-tab.component.less66
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-information-tab.component.html30
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-information-tab.component.ts39
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-members-tab.component.html31
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-members-tab.component.less13
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-members-tab.component.ts133
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-properties-tab.component.html23
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-properties-tab.component.less0
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-properties-tab.component.ts64
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-tabs.component.html11
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-tabs.component.ts67
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-tabs.module.ts71
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-information-tab.component.html34
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-information-tab.component.ts39
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-properties-tab.component.html23
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-properties-tab.component.less0
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-properties-tab.component.ts64
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-tabs.component.html12
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-tabs.component.ts72
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-tabs.module.ts68
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-targets-tab.component.html32
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-targets-tab.component.less12
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-targets-tab.component.ts145
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/panel/panel.component.html34
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/panel/panel.component.less11
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/panel/panel.component.ts60
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/panel/panel.module.ts54
-rw-r--r--catalog-ui/src/app/ng2/pages/connection-wizard/connection-wizard.service.ts13
-rw-r--r--catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.html9
-rw-r--r--catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.ts271
-rw-r--r--catalog-ui/src/app/ng2/pages/service-path-creator/link-row/link-row.component.html50
-rw-r--r--catalog-ui/src/app/ng2/pages/service-path-creator/link-row/link-row.component.ts35
-rw-r--r--catalog-ui/src/app/ng2/pages/service-path-creator/service-path-creator.component.html13
-rw-r--r--catalog-ui/src/app/ng2/pages/service-path-creator/service-path-creator.component.ts20
-rw-r--r--catalog-ui/src/app/ng2/pages/service-paths-list/service-paths-list.component.html6
-rw-r--r--catalog-ui/src/app/ng2/pages/service-paths-list/service-paths-list.component.less3
-rw-r--r--catalog-ui/src/app/ng2/pages/service-paths-list/service-paths-list.component.ts4
61 files changed, 2534 insertions, 171 deletions
diff --git a/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-models/ui-component-to-upgrade.ts b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-models/ui-component-to-upgrade.ts
new file mode 100644
index 0000000000..97fb71e210
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-models/ui-component-to-upgrade.ts
@@ -0,0 +1,103 @@
+import {ComponentState} from "../../../../utils/constants";
+import {IDependenciesServerResponse} from "../../../services/responses/dependencies-server-response";
+import {UiBaseObject} from "../../../../models/ui-models/ui-base-object";
+
+/**
+ * Created by ob0695 on 5/1/2018.
+ */
+export enum AutomatedUpgradeInstanceType {
+ VF, SERVICE_PROXY, ALLOTTED_RESOURCE
+}
+export class ServiceContainerToUpgradeUiObject extends UiBaseObject {
+
+ icon:string;
+ version:string;
+ isLock:boolean; // true if service is in check-out or ceritification-in-progress
+ vspInstances:Array<VspInstanceUiObject>; // list of instances of the vsp contain in the service - intances can be vf, proxy or allotted
+ isAlreadyUpgrade:boolean; // true if all instances is in latest version
+
+ constructor(componentToUpgrade:IDependenciesServerResponse) {
+ super(componentToUpgrade.uniqueId, componentToUpgrade.type, componentToUpgrade.name);
+ this.icon = componentToUpgrade.icon;
+ this.version = componentToUpgrade.version;
+ this.isAlreadyUpgrade = true;
+ this.isLock = componentToUpgrade.state === ComponentState.CERTIFICATION_IN_PROGRESS || componentToUpgrade.state === ComponentState.NOT_CERTIFIED_CHECKOUT;
+ this.vspInstances = [];
+ }
+
+ public addVfInstance = (vsp: IDependenciesServerResponse, latestVersion:string):void => {
+ let isNeededUpgrade = parseInt(vsp.version) < parseInt(latestVersion);
+ this.vspInstances.push(new VspInstanceUiObject(vsp.uniqueId, vsp.name, vsp.version, vsp.icon));
+ if (isNeededUpgrade) {
+ this.isAlreadyUpgrade = false;
+ }
+ }
+
+ public addProxyInstance = (vsp: IDependenciesServerResponse, isNeededUpgrade:boolean, instanceName:string):void => {
+ this.vspInstances.push(new ProxyVspInstanceUiObject(vsp.uniqueId, vsp.name, vsp.version, vsp.icon, instanceName));
+ if (isNeededUpgrade) {
+ this.isAlreadyUpgrade = false;
+ }
+ }
+
+ public addAllottedResourceInstance = (vsp: IDependenciesServerResponse, isNeededUpgrade:boolean, instanceName:string, vfName:string, vfId:string):void => {
+ this.vspInstances.push(new AllottedResourceInstanceUiObject(vsp.uniqueId, vsp.name, vsp.version, vsp.icon, instanceName, vfName, vfId));
+ if (isNeededUpgrade) {
+ this.isAlreadyUpgrade = false;
+ }
+ }
+
+ public addMultipleInstances = (vsp: IDependenciesServerResponse, vspLatestVersion:string, instancesNames:Array<string>, allottedOriginVf: IDependenciesServerResponse):void => {
+ _.forEach(instancesNames, (instanceName:string) => {
+ let isNeededUpgrade = parseInt(vsp.version) < parseInt(vspLatestVersion);
+ if (allottedOriginVf) {
+ this.addAllottedResourceInstance(vsp, isNeededUpgrade, instanceName, allottedOriginVf.name, allottedOriginVf.uniqueId);
+ } else {
+ this.addProxyInstance(vsp, isNeededUpgrade, instanceName);
+ }
+ })
+ }
+}
+
+export class VspInstanceUiObject {
+
+ vspName:string;
+ vspVersion:string;
+ vspId:string;
+ icon:string;
+ instanceType:AutomatedUpgradeInstanceType;
+
+ constructor(uniqueId:string, vspName:string, vspVersion:string, icon:string) {
+ this.vspId = uniqueId;
+ this.vspName = vspName;
+ this.vspVersion = vspVersion;
+ this.icon = icon;
+ this.instanceType = AutomatedUpgradeInstanceType.VF;
+ }
+}
+
+export class ProxyVspInstanceUiObject extends VspInstanceUiObject {
+
+ instanceName:string;
+
+ constructor(uniqueId:string, vspName:string, vspVersion:string, icon:string, instanceName: string) {
+ super(uniqueId, vspName, vspVersion, icon);
+ this.instanceName = instanceName;
+ this.instanceType = AutomatedUpgradeInstanceType.SERVICE_PROXY;
+ }
+}
+
+export class AllottedResourceInstanceUiObject extends VspInstanceUiObject {
+
+ instanceName:string;
+ originVfName:string;
+ originVfId:string;
+
+ constructor(uniqueId:string, vspName:string, vspVersion:string, icon:string, instanceName:string, originVfName:string, originVfId:string) {
+ super(uniqueId, vspName, vspVersion, icon)
+ this.instanceName = instanceName;
+ this.originVfId = originVfId;
+ this.originVfName = originVfName;
+ this.instanceType = AutomatedUpgradeInstanceType.ALLOTTED_RESOURCE;
+ }
+}
diff --git a/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-status/automated-upgrade-status.component.html b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-status/automated-upgrade-status.component.html
new file mode 100644
index 0000000000..12a3b72b92
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-status/automated-upgrade-status.component.html
@@ -0,0 +1,10 @@
+<div class="automated-upgrade-component">
+ <span innerHTML="{{statusText}}"> </span>
+ <div class="components-to-upgrade-list">
+ <ul>
+ <li class="components-to-upgrade-list-item " *ngFor="let component of upgradedComponentsList">
+ <upgrade-list-status-item [upgradedComponent]="component" [upgradeComponentStatus]="upgradeStatusMap[component.name]"></upgrade-list-status-item>
+ </li>
+ </ul>
+ </div>
+</div>
diff --git a/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-status/automated-upgrade-status.component.ts b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-status/automated-upgrade-status.component.ts
new file mode 100644
index 0000000000..0bc342ce65
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-status/automated-upgrade-status.component.ts
@@ -0,0 +1,24 @@
+/**
+ * Created by ob0695 on 4/24/2018.
+ */
+import {Component, Input} from "@angular/core";
+import Dictionary = _.Dictionary;
+import {AutomatedUpgradeStatusResponse} from "../../../services/responses/automated-upgrade-response";
+import {ServiceContainerToUpgradeUiObject} from "../automated-upgrade-models/ui-component-to-upgrade";
+
+@Component({
+ selector: 'automated-upgrade-status',
+ templateUrl: './automated-upgrade-status.component.html',
+ styleUrls: ['./../automated-upgrade.component.less']
+})
+export class AutomatedUpgradeStatusComponent {
+
+ @Input() upgradedComponentsList: Array<ServiceContainerToUpgradeUiObject>;
+ @Input() upgradeStatusMap: Dictionary<AutomatedUpgradeStatusResponse>;
+ @Input() statusText: string;
+
+ constructor () {
+
+ }
+
+}
diff --git a/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/list-item-inner-content/list-item-inner-content.component.html b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/list-item-inner-content/list-item-inner-content.component.html
new file mode 100644
index 0000000000..2a03d94c8c
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/list-item-inner-content/list-item-inner-content.component.html
@@ -0,0 +1,25 @@
+<ul class="list-item-inner-content">
+ <li *ngFor="let vspInstance of vspInstances" class="first-line">
+ <div [ngSwitch]="vspInstance.instanceType">
+
+ <div *ngSwitchCase="automatedUpgradeType.VF">
+ <upgrade-line-item arrowName="arrow2-right-child" text="{{vspInstance.vspName}} ({{vspInstance.vspVersion}})"></upgrade-line-item>
+ </div>
+
+ <div *ngSwitchCase="automatedUpgradeType.SERVICE_PROXY">
+ <upgrade-line-item arrowName="arrow2-right-child" prefix="Service Proxy: " text="{{vspInstance.instanceName}}"></upgrade-line-item>
+ <div class="second-line">
+ <upgrade-line-item arrowName="arrow2-right-child" icon="{{vspInstance.icon}}" text="{{ vspInstance.vspName }} ({{vspInstance.vspVersion}})"></upgrade-line-item>
+ </div>
+ </div>
+
+ <div *ngSwitchCase="automatedUpgradeType.ALLOTTED_RESOURCE">
+ <upgrade-line-item class="allotted-resource-line" arrowName="arrow2-right-child" prefix=" VNF: " text="{{vspInstance.originVfName}}"></upgrade-line-item>
+ <upgrade-line-item arrowName="arrow2-right" prefix=" VFC: " text="{{vspInstance.instanceName}}"></upgrade-line-item>
+ <div class="second-line">
+ <upgrade-line-item arrowName="arrow2-right-child" icon="vspInstance.icon" prefix=" VFC: " text="{{ vspInstance.vspName }} ({{vspInstance.vspVersion}})"></upgrade-line-item>
+ </div>
+ </div>
+ </div>
+ </li>
+</ul> \ No newline at end of file
diff --git a/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/list-item-inner-content/list-item-inner-content.component.less b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/list-item-inner-content/list-item-inner-content.component.less
new file mode 100644
index 0000000000..24f8107e84
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/list-item-inner-content/list-item-inner-content.component.less
@@ -0,0 +1,25 @@
+@import "./../../../../../../assets/styles/override";
+
+.list-item-inner-content {
+ .first-line {
+
+ padding: 2px 20px 2px 65px;
+ border-bottom: 1px solid @sdcui_color_silver;
+
+ &:last-child {
+ border-bottom: none;
+ }
+ }
+
+ .second-line {
+ padding-left: 45px;
+ font-weight: bold;
+ }
+
+ .allotted-resource-line {
+
+ float: left;
+ margin-right: 15px;
+
+ }
+} \ No newline at end of file
diff --git a/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/list-item-inner-content/list-item-inner-content.component.ts b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/list-item-inner-content/list-item-inner-content.component.ts
new file mode 100644
index 0000000000..0fa467c3ae
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/list-item-inner-content/list-item-inner-content.component.ts
@@ -0,0 +1,24 @@
+/**
+ * Created by ob0695 on 5/7/2018.
+ */
+/**
+ * Created by ob0695 on 5/2/2018.
+ */
+import {Component, Input} from "@angular/core";
+import {
+ VspInstanceUiObject,
+ AutomatedUpgradeInstanceType
+} from "../../automated-upgrade-models/ui-component-to-upgrade";
+
+
+@Component({
+ selector: 'upgrade-list-item-inner-content',
+ templateUrl: './list-item-inner-content.component.html',
+ styleUrls: ['./list-item-inner-content.component.less']
+})
+export class UpgradeListItemInnerContent {
+
+ @Input() vspInstances:Array<VspInstanceUiObject>;
+
+ automatedUpgradeType = AutomatedUpgradeInstanceType;
+}
diff --git a/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/list-item-order-pipe/list-item-order-pipe.ts b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/list-item-order-pipe/list-item-order-pipe.ts
new file mode 100644
index 0000000000..abebe0bdd8
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/list-item-order-pipe/list-item-order-pipe.ts
@@ -0,0 +1,42 @@
+import {Pipe, PipeTransform} from "@angular/core";
+import {ServiceContainerToUpgradeUiObject} from "../../automated-upgrade-models/ui-component-to-upgrade";
+
+/*
+ This filter needs to return all not upgraded components sorted by name first, after that all upgraded components sorted by name
+ And in the end all the locked components sorted by name
+ */
+
+@Pipe({
+ name: 'upgradeListItemOrderBy'
+})
+export class UpgradeListItemOrderPipe implements PipeTransform {
+
+ private orderByName = (firstName:string, secondName:string):number => {
+ var textA = firstName.toLocaleLowerCase();
+ var textB = secondName.toLocaleLowerCase();
+ return (textA < textB) ? -1 : (textA > textB) ? 1 : 0;
+ }
+
+ transform(array:Array<ServiceContainerToUpgradeUiObject>):Array<ServiceContainerToUpgradeUiObject> {
+ array.sort((first:ServiceContainerToUpgradeUiObject, second:ServiceContainerToUpgradeUiObject) => {
+ if (first.isLock && second.isLock) {
+ return this.orderByName(first.name, second.name);
+ } else if (first.isLock) {
+ return 1;
+ } else if (second.isLock) {
+ return -1;
+ } else {
+ if (first.isAlreadyUpgrade && second.isAlreadyUpgrade) {
+ return this.orderByName(first.name, second.name);
+ } else if (first.isAlreadyUpgrade) {
+ return 1;
+ } else if (second.isAlreadyUpgrade) {
+ return -1;
+ } else {
+ return this.orderByName(first.name, second.name);
+ }
+ }
+ });
+ return array;
+ }
+} \ No newline at end of file
diff --git a/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/upgrade-line-item/upgrade-line-item.component.html b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/upgrade-line-item/upgrade-line-item.component.html
new file mode 100644
index 0000000000..e848283f67
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/upgrade-line-item/upgrade-line-item.component.html
@@ -0,0 +1,6 @@
+<div class="upgrade-line-item">
+ <svg-icon *ngIf="arrowName" name="{{arrowName}}" size="medium" mode="secondary"></svg-icon>
+ <div *ngIf="icon" class="line-item-icon small sprite-services-icons {{icon}}"></div>
+ <span *ngIf="prefix" class="line-item-prefix">{{prefix}}</span>
+ <span class="line-item-text">{{text}}</span>
+</div> \ No newline at end of file
diff --git a/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/upgrade-line-item/upgrade-line-item.component.less b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/upgrade-line-item/upgrade-line-item.component.less
new file mode 100644
index 0000000000..d558e881c2
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/upgrade-line-item/upgrade-line-item.component.less
@@ -0,0 +1,17 @@
+.upgrade-line-item{
+
+ display: flex;
+ align-items: center;
+
+ .line-item-icon {
+ margin-left: 10px;
+ }
+
+ .line-item-prefix {
+ margin-left: 7px;
+ }
+
+ .line-item-text {
+ margin-left: 7px;
+ }
+} \ No newline at end of file
diff --git a/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/upgrade-line-item/upgrade-line-item.component.ts b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/upgrade-line-item/upgrade-line-item.component.ts
new file mode 100644
index 0000000000..b256d7efe8
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/upgrade-line-item/upgrade-line-item.component.ts
@@ -0,0 +1,19 @@
+import {Component, Input} from "@angular/core";
+
+@Component({
+ selector: 'upgrade-line-item',
+ templateUrl: './upgrade-line-item.component.html',
+ styleUrls: ['./upgrade-line-item.component.less']
+})
+
+export class UpgradeLineItemComponent {
+
+ @Input() arrowName:string;
+ @Input() icon:string;
+ @Input() prefix:string;
+ @Input() text:string;
+
+ constructor() {
+
+ }
+}
diff --git a/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/upgrade-list-item-status/upgrade-list-status-item.component.html b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/upgrade-list-item-status/upgrade-list-status-item.component.html
new file mode 100644
index 0000000000..c6d3add7e6
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/upgrade-list-item-status/upgrade-list-status-item.component.html
@@ -0,0 +1,13 @@
+<div class="components-to-upgrade-list-item">
+ <div class="component-to-upgrade-data">
+ <div class="component-to-upgrade-icon small sprite-services-icons {{upgradedComponent.icon}}"></div>
+ <span class="component-to-upgrade-name">{{upgradedComponent.name}} ({{upgradedComponent.version}})</span>
+ <svg-icon-label class="upgraded-component-status" *ngIf="upgradeComponentStatus.status === 'OK'"
+ name="success-circle-o" mode="success" size="medium" clickable="false"></svg-icon-label>
+ <svg-icon-label class="upgraded-component-status" *ngIf="upgradeComponentStatus.status !== 'OK'"
+ name="x-circle-o" mode="error"
+ size="medium" [label]="'Update Failed'" clickable="false" disabled="false" labelPlacement="left"></svg-icon-label>
+ </div>
+
+ <upgrade-list-item-inner-content [vspInstances]="upgradedComponent.vspInstances"></upgrade-list-item-inner-content>
+</div> \ No newline at end of file
diff --git a/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/upgrade-list-item-status/upgrade-list-status-item.component.ts b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/upgrade-list-item-status/upgrade-list-status-item.component.ts
new file mode 100644
index 0000000000..726bc67fcf
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/upgrade-list-item-status/upgrade-list-status-item.component.ts
@@ -0,0 +1,19 @@
+import {Component, Input} from "@angular/core";
+import {AutomatedUpgradeStatusResponse} from "../../../../services/responses/automated-upgrade-response";
+import {ServiceContainerToUpgradeUiObject} from "../../automated-upgrade-models/ui-component-to-upgrade";
+
+@Component({
+ selector: 'upgrade-list-status-item',
+ templateUrl: './upgrade-list-status-item.component.html',
+ styleUrls: ['./../upgrade-list-item.component.less']
+})
+export class UpgradeListItemStatusComponent {
+
+ @Input() upgradedComponent: ServiceContainerToUpgradeUiObject;
+ @Input() upgradeComponentStatus: AutomatedUpgradeStatusResponse;
+
+ constructor () {
+
+ }
+
+}
diff --git a/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/upgrade-list-item.component.less b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/upgrade-list-item.component.less
new file mode 100644
index 0000000000..4507929b7f
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/upgrade-list-item.component.less
@@ -0,0 +1,44 @@
+@import "./../../../../../assets/styles/override";
+
+.components-to-upgrade-list-item {
+ border: 1px solid @sdcui_color_light-gray;
+ box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.11);
+ margin-bottom: 10px;
+ line-height: 40px;
+
+ .component-to-upgrade-data {
+ display: flex;
+ background-color: @sdcui_color_light-silver;
+ height: 40px;
+ padding: 0 10px;
+ align-items: center;
+
+ .component-to-upgrade-icon {
+ margin-left: 26px;
+ }
+
+ .component-to-upgrade-name {
+ margin-left: 8px;
+ }
+
+ .component-to-upgrade-checkbox {
+ height: 24px; // Workaround can not vertical center
+ }
+
+ .upgraded-component-status {
+ margin-left: auto;
+ }
+ }
+
+ .vsp-data {
+ align-items: center;
+ display: flex;
+ border-bottom: 1px solid @sdcui_color_silver;
+ padding: 0 10px 0 64px;
+ .vsp-data-label {
+ color: @sdcui_color_text-black;
+ margin-left: 7px;
+ font-weight: 600;
+ }
+ }
+} \ No newline at end of file
diff --git a/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/upgrade-list-item/upgrade-list-item.component.html b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/upgrade-list-item/upgrade-list-item.component.html
new file mode 100644
index 0000000000..6e6af0cd1c
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/upgrade-list-item/upgrade-list-item.component.html
@@ -0,0 +1,19 @@
+<div class="components-to-upgrade-list-item ">
+ <div class="component-to-upgrade-data">
+ <sdc-checkbox class="component-to-upgrade-checkbox"
+ *ngIf="!componentToUpgrade.isAlreadyUpgrade && !componentToUpgrade.isLock"
+ [checked]="true"
+ [disabled]="disabled"
+ (checkedChange)="onComponentChecked(componentToUpgrade.uniqueId)">
+ </sdc-checkbox>
+ <svg-icon *ngIf="componentToUpgrade.isAlreadyUpgrade" name="success-circle-o" mode="success"
+ size="medium"></svg-icon>
+ <svg-icon *ngIf="!componentToUpgrade.isAlreadyUpgrade && componentToUpgrade.isLock" name="locked" mode="info"
+ size="small"></svg-icon>
+ <div class="component-to-upgrade-icon small sprite-services-icons {{componentToUpgrade.icon}}"></div>
+ <span class="component-to-upgrade-name">{{componentToUpgrade.name}} ({{componentToUpgrade.version}})</span>
+ </div>
+
+ <upgrade-list-item-inner-content [vspInstances]="componentToUpgrade.vspInstances"></upgrade-list-item-inner-content>
+
+</div> \ No newline at end of file
diff --git a/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/upgrade-list-item/upgrade-list-item.component.ts b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/upgrade-list-item/upgrade-list-item.component.ts
new file mode 100644
index 0000000000..806b83126f
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade-ui-components/upgrade-list-item/upgrade-list-item.component.ts
@@ -0,0 +1,23 @@
+import {Component, Input, Output, EventEmitter} from "@angular/core";
+import {ServiceContainerToUpgradeUiObject, AutomatedUpgradeInstanceType} from "../../automated-upgrade-models/ui-component-to-upgrade";
+
+@Component({
+ selector: 'upgrade-list-item',
+ templateUrl: './upgrade-list-item.component.html',
+ styleUrls: ['./../upgrade-list-item.component.less']
+})
+export class UpgradeListItemComponent {
+
+ @Input() componentToUpgrade:ServiceContainerToUpgradeUiObject;
+ @Input() disabled: boolean;
+ @Output() onCheckedChange:EventEmitter<any> = new EventEmitter<any>();
+
+ constructor() {
+ }
+
+ onComponentChecked = ():void => {
+ this.onCheckedChange.emit();
+ }
+
+
+}
diff --git a/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade.component.html b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade.component.html
new file mode 100644
index 0000000000..67e7f08436
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade.component.html
@@ -0,0 +1,25 @@
+<div class="automated-upgrade-component">
+
+ <div *ngIf="certificationStatusText" class="certification-status">
+ <svg-icon-label
+ name="success-circle-o"
+ mode="success"
+ size="medium"
+ clickable="false"
+ disabled="false"
+ labelPlacement="right">
+ </svg-icon-label>
+ <span class="certification-status-text">{{certificationStatusText}}</span>
+ </div>
+
+ <div>
+ <span innerHTML="{{informationText}}"> </span>
+ <div class="components-to-upgrade-list">
+ <ul>
+ <li *ngFor="let component of componentsToUpgrade | upgradeListItemOrderBy">
+ <upgrade-list-item (onCheckedChange)= "onComponentSelected(component.uniqueId)" [disabled]="disabled" [componentToUpgrade]="component"></upgrade-list-item>
+ </li>
+ </ul>
+ </div>
+ </div>
+</div> \ No newline at end of file
diff --git a/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade.component.less b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade.component.less
new file mode 100644
index 0000000000..2ab21303d6
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade.component.less
@@ -0,0 +1,23 @@
+.automated-upgrade-component {
+
+ min-height: 280px;
+ .certification-status {
+ border: 1px solid #4ca90c;
+ border-left: 5px solid #4ca90c;
+ margin-bottom: 20px;
+ padding: 5px 5px 5px 10px;
+ font-weight: bold;
+ display: flex;
+ line-height: 21px;
+
+ .certification-status-text {
+ padding-left: 5px;
+ }
+ }
+ .components-to-upgrade-list {
+
+ overflow: auto;
+ max-height: 300px;
+ margin-top: 15px;
+ }
+} \ No newline at end of file
diff --git a/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade.component.ts b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade.component.ts
new file mode 100644
index 0000000000..9ae73497ef
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade.component.ts
@@ -0,0 +1,65 @@
+/**
+ * Created by ob0695 on 4/18/2018.
+ */
+/*-
+ * ============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, Input, Inject, forwardRef} from "@angular/core";
+import {TranslateService} from "../../shared/translator/translate.service";
+import {ServiceContainerToUpgradeUiObject} from "./automated-upgrade-models/ui-component-to-upgrade";
+import {AutomatedUpgradeService} from "./automated-upgrade.service";
+
+@Component({
+ selector: 'upgrade-vsp',
+ templateUrl: './automated-upgrade.component.html',
+ styleUrls: ['./automated-upgrade.component.less'],
+ providers: [TranslateService]
+})
+export class AutomatedUpgradeComponent {
+
+ @Input() componentsToUpgrade: Array<ServiceContainerToUpgradeUiObject>;
+ @Input() certificationStatusText: string;
+ @Input() informationText: string;
+ @Input() disabled: string;
+ private selectedComponentsToUpgrade: Array<string> = [];
+
+ constructor (@Inject(forwardRef(() => AutomatedUpgradeService)) private automatedUpgradeService: AutomatedUpgradeService) {
+ }
+
+ ngOnInit(): void { // We need to check all elements that needed upgrade as default
+ this.selectedComponentsToUpgrade = _.filter(this.componentsToUpgrade, (componentToUpgrade:ServiceContainerToUpgradeUiObject) => {
+ return !componentToUpgrade.isAlreadyUpgrade && !componentToUpgrade.isLock;
+ }).map(element => element.uniqueId)
+ }
+
+ onComponentSelected = (uniqueId:string):void => {
+
+ if(this.selectedComponentsToUpgrade.indexOf(uniqueId) > -1) {
+ this.selectedComponentsToUpgrade = _.without(this.selectedComponentsToUpgrade, uniqueId);
+ } else {
+ this.selectedComponentsToUpgrade.push(uniqueId);
+ }
+ if(this.selectedComponentsToUpgrade.length === 0) {
+ this.automatedUpgradeService.changeUpgradeButtonState(true);
+ } else {
+ this.automatedUpgradeService.changeUpgradeButtonState(false);
+ }
+ }
+}
diff --git a/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade.module.ts b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade.module.ts
new file mode 100644
index 0000000000..19f6412071
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade.module.ts
@@ -0,0 +1,34 @@
+/**
+ * Created by ob0695 on 4/18/2018.
+ */
+import { NgModule } from "@angular/core";
+import {SdcUiComponentsModule} from "sdc-ui/lib/angular/index";
+import {CommonModule} from "@angular/common";
+import {AutomatedUpgradeStatusComponent} from "./automated-upgrade-status/automated-upgrade-status.component";
+import {AutomatedUpgradeComponent} from "./automated-upgrade.component";
+import {UpgradeListItemComponent} from "./automated-upgrade-ui-components/upgrade-list-item/upgrade-list-item.component";
+import {UpgradeListItemStatusComponent} from "./automated-upgrade-ui-components/upgrade-list-item-status/upgrade-list-status-item.component";
+import {TranslateService} from "../../shared/translator/translate.service";
+import {UpgradeListItemInnerContent} from "./automated-upgrade-ui-components/list-item-inner-content/list-item-inner-content.component";
+import {UpgradeLineItemComponent} from "./automated-upgrade-ui-components/upgrade-line-item/upgrade-line-item.component";
+import {UpgradeListItemOrderPipe} from "./automated-upgrade-ui-components/list-item-order-pipe/list-item-order-pipe";
+
+@NgModule({
+ declarations: [
+ AutomatedUpgradeStatusComponent,
+ UpgradeListItemComponent,
+ UpgradeListItemStatusComponent,
+ AutomatedUpgradeComponent,
+ UpgradeListItemInnerContent,
+ UpgradeLineItemComponent,
+ UpgradeListItemOrderPipe
+ ],
+ imports: [CommonModule, SdcUiComponentsModule],
+ exports: [],
+ entryComponents: [
+ AutomatedUpgradeComponent, AutomatedUpgradeStatusComponent
+ ],
+ providers: [TranslateService]
+})
+export class AutomatedUpgradeModule {
+} \ No newline at end of file
diff --git a/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade.service.ts b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade.service.ts
new file mode 100644
index 0000000000..0acfececaa
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/automated-upgrade/automated-upgrade.service.ts
@@ -0,0 +1,279 @@
+import {SdcUiComponents} from "sdc-ui/lib/angular";
+import {Injectable, Inject} from "@angular/core";
+import {IModalConfig} from "sdc-ui/lib/angular/modals/models/modal-config";
+import {AutomatedUpgradeComponent} from "./automated-upgrade.component";
+import {Component} from "../../../models/components/component";
+import {ComponentServiceNg2} from "../../services/component-services/component.service";
+import {GeneralStatus, ComponentType} from "../../../utils/constants";
+import {IDependenciesServerResponse} from "../../services/responses/dependencies-server-response";
+import {AutomatedUpgradeStatusComponent} from "./automated-upgrade-status/automated-upgrade-status.component";
+import {AutomatedUpgradeStatusResponse} from "../../services/responses/automated-upgrade-response";
+import Dictionary = _.Dictionary;
+import {TranslateService, ITranslateArgs} from "../../shared/translator/translate.service";
+import {
+ ServiceContainerToUpgradeUiObject,
+ AllottedResourceInstanceUiObject, VspInstanceUiObject
+} from "./automated-upgrade-models/ui-component-to-upgrade";
+
+export interface IAutomatedUpgradeRequestObj {
+ serviceId:string;
+ resourceId?:string;
+}
+
+export enum Placement {
+ left = "left"
+}
+
+@Injectable()
+export class AutomatedUpgradeService {
+
+ private vspComponent:Component;
+ private uiComponentsToUpgrade:Array<ServiceContainerToUpgradeUiObject>;
+ private componentType:string;
+
+ constructor(private modalService:SdcUiComponents.ModalService,
+ private componentService:ComponentServiceNg2,
+ private translateService:TranslateService) {
+ }
+
+
+ public convertToServerRequest = (selectedServices:Array<string>):Array<IAutomatedUpgradeRequestObj> => {
+
+ let automatedRequest:Array<IAutomatedUpgradeRequestObj> = [];
+ _.forEach(selectedServices, (serviceId:string) => {
+ let serviceToUpgrade:ServiceContainerToUpgradeUiObject = _.find(this.uiComponentsToUpgrade, (service:ServiceContainerToUpgradeUiObject) => {
+ return serviceId === service.uniqueId;
+ });
+
+ if (serviceToUpgrade.vspInstances[0] instanceof AllottedResourceInstanceUiObject) { // If this is allotted resource instances, we need to take the origin vf id (all the instances have the save origin vspId
+ automatedRequest.push({
+ serviceId: serviceId,
+ resourceId: (<AllottedResourceInstanceUiObject> serviceToUpgrade.vspInstances[0]).originVfId
+ });
+ } else {
+ automatedRequest.push({serviceId: serviceId});
+ }
+ });
+ return automatedRequest;
+ }
+
+ private getStatusText = (statusMap:Dictionary<AutomatedUpgradeStatusResponse>):string => {
+ let failedUpgraded = _.filter(_.flatMap(statusMap), (upgradeStatus:AutomatedUpgradeStatusResponse) => {
+ return upgradeStatus.status !== GeneralStatus.OK
+ });
+
+ if (failedUpgraded.length > 0) {
+ return this.getTextByComponentType("_UPGRADE_STATUS_FAIL");
+ }
+ return this.getTextByComponentType("_UPGRADE_STATUS_SUCCESS");
+ }
+
+ private disabledAllModalButtons = ():void => {
+ this.modalService.getCurrentInstance().innerModalContent.instance.disabled = true;
+ this.modalService.getCurrentInstance().buttons[0].show_spinner = true;
+ this.modalService.getCurrentInstance().buttons[1].disabled = true;
+ }
+
+ public changeUpgradeButtonState = (isDisabled:boolean):void => {
+ if (this.modalService.getCurrentInstance().buttons[0].disabled !== isDisabled) {
+ this.modalService.getCurrentInstance().buttons[0].disabled = isDisabled;
+ }
+ }
+
+ //TODO We will need to replace this function after sdc-ui modal new design, this is just a workaround
+ public automatedUpgrade = ():void => {
+
+ let selectedServices = this.modalService.getCurrentInstance().innerModalContent.instance.selectedComponentsToUpgrade;
+ this.disabledAllModalButtons();
+ this.componentService.automatedUpgrade(this.vspComponent.componentType, this.vspComponent.uniqueId, this.convertToServerRequest(selectedServices)).subscribe((automatedUpgradeStatus:any) => {
+
+ if (automatedUpgradeStatus.status === GeneralStatus.OK) {
+
+ let statusMap:Dictionary<AutomatedUpgradeStatusResponse> = _.keyBy(automatedUpgradeStatus.componentToUpgradeStatus, 'name');
+ // In the status modal we only showing the upgraded component that the user selected, not the entire list
+ let upgradedComponent:Array<ServiceContainerToUpgradeUiObject> = _.filter(this.uiComponentsToUpgrade, (component:ServiceContainerToUpgradeUiObject) => {
+ return selectedServices.indexOf(component.uniqueId) > -1;
+ });
+
+ _.forEach(upgradedComponent, (upgradedComponent:ServiceContainerToUpgradeUiObject) => { // If upgrade success we need to upgrade the version all success
+ if (statusMap[upgradedComponent.name].status === GeneralStatus.OK) {
+ upgradedComponent.version = statusMap[upgradedComponent.name].version;
+ _.forEach(upgradedComponent.vspInstances, (instance:VspInstanceUiObject) => {
+ instance.vspVersion = this.vspComponent.version;
+ });
+ }
+ });
+
+ let statusModalTitle = this.getTextByComponentType("_UPGRADE_STATUS_TITLE");
+ this.modalService.getCurrentInstance().setTitle(statusModalTitle);
+ this.modalService.getCurrentInstance().getButtons().splice(0, 1); // Remove the upgrade button
+ this.modalService.getCurrentInstance().buttons[0].disabled = false; // enable close again
+ this.modalService.getCurrentInstance().innerModalContent.destroy();
+ this.modalService.createInnnerComponent(AutomatedUpgradeStatusComponent, {
+ upgradedComponentsList: upgradedComponent,
+ upgradeStatusMap: statusMap,
+ statusText: this.getStatusText(statusMap)
+ });
+ }
+ });
+ }
+
+ public isAlreadyAdded = (uniqueId:string):ServiceContainerToUpgradeUiObject => {
+ let componentToUpgrade = _.find(this.uiComponentsToUpgrade, (componentToUpgrade:ServiceContainerToUpgradeUiObject) => {
+ return componentToUpgrade.uniqueId === uniqueId;
+ });
+ return componentToUpgrade;
+ }
+
+ public initVfUpgradeData = (serviceToUpgrade:IDependenciesServerResponse, vsp:IDependenciesServerResponse) => {
+
+ let existed = this.isAlreadyAdded(serviceToUpgrade.uniqueId);
+ if (existed) { // We will take the VF with the lower version existed - only one exist all the time in vf upgrade
+ if (vsp.version < existed.vspInstances[0].vspVersion) {
+ existed.vspInstances = [];
+ existed.addVfInstance(vsp, this.vspComponent.version);
+ }
+ } else {
+ let dependencyUiObj:ServiceContainerToUpgradeUiObject = new ServiceContainerToUpgradeUiObject(serviceToUpgrade);
+ dependencyUiObj.addVfInstance(vsp, this.vspComponent.version);
+ this.uiComponentsToUpgrade.push(dependencyUiObj);
+ }
+ }
+
+ // Service data will create instances of proxy or allotted resources
+ public initServiceUpgradeData = (serviceToUpgrade:IDependenciesServerResponse, vsp:IDependenciesServerResponse, instanceNames:Array<string>, allottedOriginVf?:IDependenciesServerResponse) => {
+
+ let existedService = this.isAlreadyAdded(serviceToUpgrade.uniqueId);
+ if (existedService) {
+ existedService.addMultipleInstances(vsp, this.vspComponent.version, instanceNames, allottedOriginVf);
+ }
+ else {
+ let dependencyUiObj:ServiceContainerToUpgradeUiObject = new ServiceContainerToUpgradeUiObject(serviceToUpgrade);
+ dependencyUiObj.addMultipleInstances(vsp, this.vspComponent.version, instanceNames, allottedOriginVf);
+ this.uiComponentsToUpgrade.push(dependencyUiObj);
+ }
+ }
+
+ /*
+ The server return response of 3 level nested object
+ First level - Vsp data by version
+ Each vsp have a decencies (the services contains the vsp - By default this is vf upgrade
+ If instancesNames exist - this can be proxy or allotted
+ If we have second layer of dependencies than this is allotted
+ Since we display the data the opposite way the BE return, this function will order the data in order to display it
+ */
+ public convertToComponentsToUpgradeUiObjArray = (dependenciesServerResponse:Array<IDependenciesServerResponse>):void => {
+
+ this.uiComponentsToUpgrade = [];
+
+ _.forEach(dependenciesServerResponse, (vsp:IDependenciesServerResponse) => { // 3 nested levels - 1 level for vf, 2 level proxy, 3 levels allotted
+ if (vsp.dependencies) {
+ _.forEach(vsp.dependencies, (dependency:IDependenciesServerResponse) => {
+ if (dependency.instanceNames) { // Init service upgrade data
+ if (dependency.dependencies) {
+ _.forEach(dependency.dependencies, (serviceContainer:IDependenciesServerResponse) => { // Initiate allotted_resource instances
+ this.initServiceUpgradeData(serviceContainer, vsp, dependency.instanceNames, dependency);
+ });
+ } else { //Init service_proxy instances
+ this.initServiceUpgradeData(dependency, vsp, dependency.instanceNames);
+ }
+ } else { // Init vf upgrade data
+ this.initVfUpgradeData(dependency, vsp);
+ }
+ })
+ }
+ });
+ }
+
+ public isAllComponentsUpgraded = ():boolean => {
+ let isAllComponentUpgrade = _.filter(this.uiComponentsToUpgrade, (component:ServiceContainerToUpgradeUiObject) => {
+ return !component.isAlreadyUpgrade;
+ });
+ return isAllComponentUpgrade.length === 0;
+ }
+
+ public isAllComponentsLocked = ():boolean => {
+ let unLockedComponents = _.filter(this.uiComponentsToUpgrade, (component:ServiceContainerToUpgradeUiObject) => {
+ return !component.isLock;
+ });
+ return unLockedComponents.length === 0;
+ }
+
+ public isUpgradeNeeded = ():boolean => {
+ let neededUpgradeList = _.filter(this.uiComponentsToUpgrade, (component:ServiceContainerToUpgradeUiObject) => {
+ return !component.isLock && !component.isAlreadyUpgrade;
+ });
+ return neededUpgradeList.length > 0;
+ }
+
+ private getTextByComponentType (textLabel: string, params?:ITranslateArgs) {
+ return this.translateService.translate(this.componentType + textLabel, params);
+ }
+ public getInformationTextToDisplay = ():string => {
+
+ let isAllComponentsUpgraded = this.isAllComponentsUpgraded();
+ let isAllComponentsLocked = this.isAllComponentsLocked();
+ let params = {vspName: this.vspComponent.name, vspVersion: this.vspComponent.version};
+
+ if (this.uiComponentsToUpgrade.length === 0) {
+ return this.getTextByComponentType("_NOTHING_TO_UPGRADE", params);
+ }
+
+ switch (true) {
+
+ case this.isUpgradeNeeded():
+ {
+ return this.getTextByComponentType("_AUTOMATED_UPGRADE_WITH_COMPONENTS_TO_UPGRADE", params);
+ }
+ case !this.isUpgradeNeeded() && isAllComponentsLocked:
+ {
+ return this.getTextByComponentType("_AUTOMATED_UPGRADE_ALL_COMPONENTS_LOCKED", params);
+ }
+ case !this.isUpgradeNeeded() && !isAllComponentsLocked && isAllComponentsUpgraded:
+ {
+ return this.getTextByComponentType("_AUTOMATED_UPGRADE_ALL_COMPONENTS_UPGRADED", params);
+ }
+ case !this.isUpgradeNeeded() && !isAllComponentsLocked && !isAllComponentsUpgraded:
+ {
+ return this.getTextByComponentType("_AUTOMATED_UPGRADE_ALL_COMPONENTS_LOCKED", params);
+ }
+ }
+ }
+
+ public openAutomatedUpgradeModal = (componentsToUpgrade:Array<IDependenciesServerResponse>, component:Component, isAfterCertification?:boolean):void => {
+
+ this.vspComponent = component;
+ this.componentType = this.vspComponent.isResource() ? ComponentType.RESOURCE : ComponentType.SERVICE;
+
+ this.convertToComponentsToUpgradeUiObjArray(componentsToUpgrade);
+ let informationalText = this.getInformationTextToDisplay();
+ let modalTitle = this.getTextByComponentType("_UPGRADE_TITLE");
+ let certificationText = isAfterCertification ? this.getTextByComponentType("_CERTIFICATION_STATUS_TEXT", {resourceName: this.vspComponent.name}) : undefined;
+
+ let upgradeVspModalConfig:IModalConfig = {
+ title: modalTitle,
+ size: "md",
+ type: "custom",
+ testId: "upgradeVspModal",
+ buttons: [
+ {
+ text: this.vspComponent.isResource() ? "UPGRADE" : "UPDATE",
+ spinner_position: Placement.left,
+ size: 'sm',
+ callback: this.automatedUpgrade,
+ closeModal: false,
+ disabled: !this.isUpgradeNeeded(),
+
+ },
+ {text: 'CLOSE', size: 'sm', closeModal: true, type: 'secondary'}
+ ]
+ };
+
+ this.modalService.openCustomModal(upgradeVspModalConfig, AutomatedUpgradeComponent, {
+ componentsToUpgrade: this.uiComponentsToUpgrade,
+ informationText: informationalText,
+ certificationStatusText: certificationText
+ });
+ }
+}
+
diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-header/panel-header.component.html b/catalog-ui/src/app/ng2/pages/composition/panel/panel-header/panel-header.component.html
new file mode 100644
index 0000000000..731d6a3855
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-header/panel-header.component.html
@@ -0,0 +1,14 @@
+<div class="component-details-panel-header" data-tests-id="w-sdc-designer-sidebar-head">
+
+ <div class="icon">
+ <div class="large {{iconClassName}}">
+ <div [ngClass]="{'non-certified': nonCertified}" tooltip="Not certified"></div>
+ </div>
+ </div>
+
+ <div class="title" data-tests-id="selectedCompTitle" tooltip="&#8203;{{name}}">{{name}}</div>
+
+ <svg-icon-label *ngIf="!isViewOnly" name="edit-file-o" clickable="true" size="small" class="rename-instance" data-tests-id="renameInstance" (click)="renameInstance()"></svg-icon-label>
+ <svg-icon-label *ngIf="!isViewOnly" name="trash-o" clickable="true" size="small" class="delete-instance" data-tests-id="deleteInstance" (click)="deleteInstance()"></svg-icon-label>
+
+</div> \ No newline at end of file
diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-header/panel-header.component.less b/catalog-ui/src/app/ng2/pages/composition/panel/panel-header/panel-header.component.less
new file mode 100644
index 0000000000..9bbc765761
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-header/panel-header.component.less
@@ -0,0 +1,34 @@
+/deep/
+.component-details-panel-header {
+ display: flex;
+ flex-direction: row;
+ height: 120px;
+ align-items: center;
+
+ .icon {
+ margin: 0 20px;
+ }
+
+ .title {
+ font-size: 16px;
+ text-overflow: ellipsis;
+ max-width: 180px;
+ white-space: nowrap;
+ overflow: hidden;
+ }
+
+ .rename-instance {
+ position: absolute;
+ top: 14px;
+ right: 20px;
+ cursor: pointer;
+ }
+
+ .delete-instance {
+ position: absolute;
+ top: 14px;
+ right: 40px;
+ cursor: pointer;
+ }
+
+} \ No newline at end of file
diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-header/panel-header.component.ts b/catalog-ui/src/app/ng2/pages/composition/panel/panel-header/panel-header.component.ts
new file mode 100644
index 0000000000..ab659a3b8f
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-header/panel-header.component.ts
@@ -0,0 +1,135 @@
+/*-
+ * ============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, Input, AfterViewInit, SimpleChanges, OnInit, OnChanges } from "@angular/core";
+import { SdcUiComponents } from "sdc-ui/lib/angular";
+import { IModalConfig } from 'sdc-ui/lib/angular/modals/models/modal-config';
+import { ZoneInstanceType } from 'app/models/graph/zones/zone-instance';
+import { ValueEditComponent } from './../../../../components/ui/forms/value-edit/value-edit.component';
+import { Component as TopologyTemplate, ComponentInstance, IAppMenu } from "app/models";
+import { PoliciesService } from '../../../../services/policies.service';
+import { GroupsService } from '../../../../services/groups.service';
+import {IZoneService} from "../../../../../models/graph/zones/zone";
+import { EventListenerService, LoaderService } from "../../../../../services";
+import { GRAPH_EVENTS, EVENTS } from "../../../../../utils";
+import { UIZoneInstanceObject } from "../../../../../models/ui-models/ui-zone-instance-object";
+import { ModalButtonComponent } from "sdc-ui/lib/angular/components";
+
+@Component({
+ selector: 'ng2-composition-panel-header',
+ templateUrl: './panel-header.component.html',
+ styleUrls: ['./panel-header.component.less']
+})
+export class CompositionPanelHeaderComponent implements OnInit, OnChanges {
+
+ @Input() topologyTemplate: TopologyTemplate;
+ @Input() selectedZoneInstanceType: ZoneInstanceType;
+ @Input() selectedZoneInstanceId: string;
+ @Input() name: string;
+ @Input() nonCertified: boolean;
+ @Input() isViewOnly: boolean;
+ @Input() isLoading: boolean;
+
+ constructor(private groupsService:GroupsService, private policiesService: PoliciesService,
+ private modalService:SdcUiComponents.ModalService, private eventListenerService:EventListenerService) { }
+
+ private service:IZoneService;
+ private iconClassName: string;
+
+ ngOnInit(): void {
+ this.init();
+ }
+
+ ngOnChanges (changes:SimpleChanges):void {
+ if(changes.selectedZoneInstanceId){
+ this.init();
+ }
+ }
+
+ ngOnDestroy() {
+
+
+ }
+ private init = (): void => {
+ if (this.selectedZoneInstanceType === ZoneInstanceType.POLICY) {
+ this.iconClassName = "sprite-policy-icons policy";
+ this.service = this.policiesService;
+ } else if (this.selectedZoneInstanceType === ZoneInstanceType.GROUP) {
+ this.iconClassName = "sprite-group-icons group";
+ this.service = this.groupsService;
+ } else {
+ this.iconClassName = "sprite-resource-icons defaulticon";
+ }
+ }
+
+ private renameInstance = (): void => {
+ const modalConfig = {
+ title: "Edit Name",
+ size: "sm",
+ type: "custom",
+ testId: "renameInstanceModal",
+ buttons: [
+ {id: 'saveButton', text: 'OK', size: 'xsm', callback: this.saveInstanceName, closeModal: false},
+ {id: 'cancelButton', text: 'Cancel', size: 'sm', closeModal: true}
+ ] as ModalButtonComponent[]
+ } as IModalConfig;
+ this.modalService.openCustomModal(modalConfig, ValueEditComponent, {name: this.name, validityChangedCallback: this.enableOrDisableSaveButton});
+ };
+
+ private enableOrDisableSaveButton = (shouldEnable: boolean): void => {
+ let saveButton: ModalButtonComponent = this.modalService.getCurrentInstance().getButtonById('saveButton');
+ saveButton.disabled = !shouldEnable;
+ }
+
+ private saveInstanceName = ():void => {
+ let currentModal = this.modalService.getCurrentInstance();
+ let nameFromModal:string = currentModal.innerModalContent.instance.name;
+
+ if(nameFromModal != this.name){
+ currentModal.buttons[0].disabled = true;
+ this.service.updateName(this.topologyTemplate.componentType, this.topologyTemplate.uniqueId, this.selectedZoneInstanceId, nameFromModal).subscribe((success)=>{
+ this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_ZONE_INSTANCE_NAME_CHANGED, nameFromModal);
+ this.modalService.closeModal();
+ }, (error)=> {
+ currentModal.buttons[0].disabled = false;
+ });
+ } else {
+ this.modalService.closeModal();
+ }
+ };
+
+ private deleteInstance = (): void => {
+ let title:string = "Delete Confirmation";
+ let message:string = "Are you sure you would like to delete "+ this.name + "?";
+ this.modalService.openAlertModal(title, message, "OK", this.deleteInstanceConfirmed, "deleteInstanceModal");
+ };
+
+ private deleteInstanceConfirmed = () => {
+ this.eventListenerService.notifyObservers(EVENTS.SHOW_LOADER_EVENT + 'composition-graph');
+ this.service.deleteZoneInstance(this.topologyTemplate.componentType, this.topologyTemplate.uniqueId, this.selectedZoneInstanceId).finally(()=> {
+ this.eventListenerService.notifyObservers(EVENTS.HIDE_LOADER_EVENT + 'composition-graph');
+ }).subscribe(()=> {
+ let deletedItem:UIZoneInstanceObject = new UIZoneInstanceObject(this.selectedZoneInstanceId, this.selectedZoneInstanceType, this.name);
+ this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_DELETE_ZONE_INSTANCE, deletedItem);
+ });
+ };
+
+}
+
diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-header/panel-header.module.ts b/catalog-ui/src/app/ng2/pages/composition/panel/panel-header/panel-header.module.ts
new file mode 100644
index 0000000000..bde0a14669
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-header/panel-header.module.ts
@@ -0,0 +1,51 @@
+/*-
+ * ============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 { CompositionPanelHeaderComponent } from "./panel-header.component";
+import { UiElementsModule } from './../../../../components/ui/ui-elements.module';
+import { ValueEditComponent } from './../../../../components/ui/forms/value-edit/value-edit.component';
+import { SdcUiComponentsModule } from "sdc-ui/lib/angular";
+import { ModalFormsModule } from "app/ng2/components/ui/forms/modal-forms.module";
+
+@NgModule({
+ declarations: [
+ CompositionPanelHeaderComponent
+ ],
+ imports: [
+ BrowserModule,
+ FormsModule,
+ HttpModule,
+ UiElementsModule,
+ SdcUiComponentsModule,
+ ModalFormsModule
+ ],
+ entryComponents: [
+ CompositionPanelHeaderComponent, ValueEditComponent
+ ],
+ exports: [
+ CompositionPanelHeaderComponent
+ ],
+})
+export class CompositionPanelHeaderModule {
+
+}
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
new file mode 100644
index 0000000000..aa8e75115f
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/base/base-tab.component.less
@@ -0,0 +1,66 @@
+@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/groups/group-information-tab.component.html b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-information-tab.component.html
new file mode 100644
index 0000000000..3c875fd930
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-information-tab.component.html
@@ -0,0 +1,30 @@
+<ng2-expand-collapse state="0">
+
+ <header tooltip="General Information">General Info</header>
+
+ <content>
+ <!-- CATEGORY -->
+ <div class="component-details-panel-item">
+ <span class="name" [innerHTML]="'GENERAL_LABEL_CATEGORY' | translate"></span>
+ <span class="value" data-tests-id="rightTab_category" tooltip="Group">Group</span>
+ </div>
+
+ <!-- SUB CATEGORY -->
+ <div class="component-details-panel-item">
+ <span class="name" [innerHTML]="'GENERAL_LABEL_SUB_CATEGORY' | translate"></span>
+ <span class="value" data-tests-id="rightTab_subCategory" tooltip="Group">Group</span>
+ </div>
+
+ <!-- VERSION -->
+ <div class="component-details-panel-item">
+ <span class="name" [innerHTML]="'GENERAL_LABEL_VERSION' | translate"></span>
+ <span class="value" data-tests-id="rightTab_version" tooltip="{{group.version}}">{{group.version}}</span>
+ </div>
+
+ <!-- DESCRIPTION -->
+ <div class="component-details-panel-item description">
+ <span class="name" [innerHTML]="'GENERAL_LABEL_DESCRIPTION' | translate"></span>
+ <span class="value" ellipsis="group.description" max-chars="55" data-tests-id="rightTab_description">{{group.description}}</span>
+ </div>
+ </content>
+</ng2-expand-collapse>
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
new file mode 100644
index 0000000000..26602224da
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-information-tab.component.ts
@@ -0,0 +1,39 @@
+/*-
+ * ============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
new file mode 100644
index 0000000000..f298a39a87
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-members-tab.component.html
@@ -0,0 +1,31 @@
+<div class="w-sdc-designer-sidebar-section-title" tooltip="Members">Members
+ <svg-icon-label *ngIf="!isViewOnly"
+ class="add-members-btn"
+ name="plus-circle-o"
+ mode="primary"
+ size="medium"
+ label="ADD"
+ labelPlacement="right"
+ (click)="openAddMembersModal()">
+ </svg-icon-label>
+</div>
+<div class="expand-collapse-content">
+ <ul>
+ <li *ngFor="let member of members; let i = index" class="component-details-panel-large-item"
+ tooltip="{{member.name}}">
+ <span>{{member.name}}</span>
+ <svg-icon-label *ngIf="!isViewOnly"
+ name="trash-o"
+ clickable="true"
+ size="small"
+ class="component-details-panel-item-delete"
+ data-tests-id="delete_member"
+ (click)="deleteMember(member)"></svg-icon-label>
+ </li>
+ </ul>
+
+ <div *ngIf="members.length===0" class="component-details-panel-tab-no-data">
+ <div class="component-details-panel-tab-no-data-title">No data to display yet</div>
+ <div class="component-details-panel-tab-no-data-content">Add members to group to see members</div>
+ </div>
+</div>
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
new file mode 100644
index 0000000000..1006e864fa
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-members-tab.component.less
@@ -0,0 +1,13 @@
+/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
new file mode 100644
index 0000000000..148f2133e8
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-members-tab.component.ts
@@ -0,0 +1,133 @@
+/*-
+ * ============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<MemberUiObject>;
+
+ @Input() group: GroupInstance;
+ @Input() topologyTemplate: TopologyTemplate;
+ @Input() isViewOnly: boolean;
+ @Output() isLoading: EventEmitter<boolean> = new EventEmitter<boolean>();
+ @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<string>) => {
+ 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<MemberUiObject> = 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<MemberUiObject> = _.union(this.members, membersToAdd);
+ this.groupsService.updateMembers(this.topologyTemplate.componentType, this.topologyTemplate.uniqueId, this.group.uniqueId, updatedMembers).subscribe(
+ (updatedMembers:Array<string>) => {
+ 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<MemberUiObject> {
+
+ let optionalsMembersToAdd:Array<MemberUiObject> = [];
+
+ // 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
new file mode 100644
index 0000000000..9de489e316
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-properties-tab.component.html
@@ -0,0 +1,23 @@
+<ng2-expand-collapse state="0">
+ <header tooltip="Properties">Properties</header>
+ <content>
+ <ul>
+ <li *ngFor="let property of properties; let i = index"
+ class="i-sdc-designer-sidebar-section-content-item-property-and-attribute" data-tests-id="propertyRow">
+ <div class="i-sdc-designer-sidebar-section-content-item-property-and-attribute-label hand"
+ [attr.data-tests-id]="'propertyName_'+property.name"
+ tooltip="{{property.name}}"
+ (click)="!isViewOnly && editProperty(property)">{{property.name}}
+ </div>
+ <div class="i-sdc-designer-sidebar-section-content-item-property-value"
+ [attr.data-tests-id]="'value_'+property.name"
+ tooltip="{{property.value || property.defaultValue}}">{{property.value || property.defaultValue}}
+ </div>
+ </li>
+ </ul>
+
+ <div *ngIf="properties.length===0" class="component-details-panel-tab-no-data">
+ <div class="component-details-panel-tab-no-data-title">No properties to display</div>
+ </div>
+ </content>
+</ng2-expand-collapse>
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
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-properties-tab.component.less
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
new file mode 100644
index 0000000000..69079347c4
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-properties-tab.component.ts
@@ -0,0 +1,64 @@
+/*-
+ * ============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<PropertyModel>;
+
+ 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
new file mode 100644
index 0000000000..94b6619500
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-tabs.component.html
@@ -0,0 +1,11 @@
+<sdc-tabs>
+ <sdc-tab titleIcon="info-circle">
+ <group-information-tab [group]="group" [isViewOnly]="isViewOnly" *ngIf="group"></group-information-tab>
+ </sdc-tab>
+ <sdc-tab titleIcon="inputs-o">
+ <group-members-tab [group]="group" [topologyTemplate]="topologyTemplate" [isViewOnly]="isViewOnly" (isLoading)="setIsLoading($event)" *ngIf="group"></group-members-tab>
+ </sdc-tab>
+ <sdc-tab titleIcon="settings-o">
+ <group-properties-tab [group]="group" [topologyTemplate]="topologyTemplate" [isViewOnly]="isViewOnly" *ngIf="group"></group-properties-tab>
+ </sdc-tab>
+</sdc-tabs>
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
new file mode 100644
index 0000000000..975d5c6153
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-tabs.component.ts
@@ -0,0 +1,67 @@
+/*-
+ * ============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<boolean> = new EventEmitter<boolean>();
+
+ 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
new file mode 100644
index 0000000000..50797f862c
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-tabs.module.ts
@@ -0,0 +1,71 @@
+/*-
+ * ============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/policies/policy-information-tab.component.html b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-information-tab.component.html
new file mode 100644
index 0000000000..a1b942d56b
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-information-tab.component.html
@@ -0,0 +1,34 @@
+<ng2-expand-collapse state="0">
+ <header tooltip="General Information">General Info</header>
+ <content>
+ <!-- TYPE -->
+ <div class="component-details-panel-item">
+ <span class="name" [innerHTML]="'GENERAL_LABEL_TYPE' | translate"></span>
+ <span class="value" data-tests-id="rightTab_componentType" tooltip="{{policy.policyTypeUid}}">{{policy.policyTypeUid}}</span>
+ </div>
+
+ <!-- CATEGORY -->
+ <div class="component-details-panel-item">
+ <span class="name" [innerHTML]="'GENERAL_LABEL_CATEGORY' | translate"></span>
+ <span class="value" data-tests-id="rightTab_category" tooltip="Policy">Policy</span>
+ </div>
+
+ <!-- SUB CATEGORY -->
+ <div class="component-details-panel-item">
+ <span class="name" [innerHTML]="'GENERAL_LABEL_SUB_CATEGORY' | translate"></span>
+ <span class="value" data-tests-id="rightTab_subCategory" tooltip="Policy">Policy</span>
+ </div>
+
+ <!-- VERSION -->
+ <div class="component-details-panel-item">
+ <span class="name" [innerHTML]="'GENERAL_LABEL_VERSION' | translate"></span>
+ <span class="value" data-tests-id="rightTab_version" tooltip="{{policy.version}}">{{policy.version}}</span>
+ </div>
+
+ <!-- DESCRIPTION -->
+ <div class="component-details-panel-item description">
+ <span class="name" [innerHTML]="'GENERAL_LABEL_DESCRIPTION' | translate"></span>
+ <span class="value" ellipsis="policy.description" max-chars="55" data-tests-id="rightTab_description">{{policy.description}}</span>
+ </div>
+ </content>
+</ng2-expand-collapse>
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
new file mode 100644
index 0000000000..3639639c88
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-information-tab.component.ts
@@ -0,0 +1,39 @@
+/*-
+ * ============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
new file mode 100644
index 0000000000..9de489e316
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-properties-tab.component.html
@@ -0,0 +1,23 @@
+<ng2-expand-collapse state="0">
+ <header tooltip="Properties">Properties</header>
+ <content>
+ <ul>
+ <li *ngFor="let property of properties; let i = index"
+ class="i-sdc-designer-sidebar-section-content-item-property-and-attribute" data-tests-id="propertyRow">
+ <div class="i-sdc-designer-sidebar-section-content-item-property-and-attribute-label hand"
+ [attr.data-tests-id]="'propertyName_'+property.name"
+ tooltip="{{property.name}}"
+ (click)="!isViewOnly && editProperty(property)">{{property.name}}
+ </div>
+ <div class="i-sdc-designer-sidebar-section-content-item-property-value"
+ [attr.data-tests-id]="'value_'+property.name"
+ tooltip="{{property.value || property.defaultValue}}">{{property.value || property.defaultValue}}
+ </div>
+ </li>
+ </ul>
+
+ <div *ngIf="properties.length===0" class="component-details-panel-tab-no-data">
+ <div class="component-details-panel-tab-no-data-title">No properties to display</div>
+ </div>
+ </content>
+</ng2-expand-collapse>
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
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-properties-tab.component.less
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
new file mode 100644
index 0000000000..5862135df2
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-properties-tab.component.ts
@@ -0,0 +1,64 @@
+/*-
+ * ============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<PropertyModel>;
+
+ 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
new file mode 100644
index 0000000000..b11ad7ebf9
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-tabs.component.html
@@ -0,0 +1,12 @@
+<sdc-tabs>
+ <sdc-tab titleIcon="info-circle">
+ <policy-information-tab [policy]="policy" [isViewOnly]="isViewOnly" *ngIf="policy"></policy-information-tab>
+ </sdc-tab>
+ <sdc-tab titleIcon="inputs-o">
+ <policy-targets-tab [policy]="policy" [topologyTemplate]="topologyTemplate" [isViewOnly]="isViewOnly" (isLoading)="setIsLoading($event)" *ngIf="policy"></policy-targets-tab>
+ </sdc-tab>
+ <sdc-tab titleIcon="settings-o">
+ <policy-properties-tab [policy]="policy" [topologyTemplate]="topologyTemplate" [isViewOnly]="isViewOnly" *ngIf="policy"></policy-properties-tab>
+ </sdc-tab>
+</sdc-tabs>
+
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
new file mode 100644
index 0000000000..1e2739901d
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-tabs.component.ts
@@ -0,0 +1,72 @@
+/*-
+ * ============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<boolean> = new EventEmitter<boolean>();
+
+ 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
new file mode 100644
index 0000000000..38dc19e1af
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-tabs.module.ts
@@ -0,0 +1,68 @@
+/*-
+ * ============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
new file mode 100644
index 0000000000..097b3a4584
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-targets-tab.component.html
@@ -0,0 +1,32 @@
+<div class="w-sdc-designer-sidebar-section-title" titleTooltip="Targets">Targets
+ <svg-icon-label *ngIf="!isViewOnly"
+ class="add-policy-button"
+ name="plus-circle-o"
+ mode="primary"
+ size="medium"
+ label="ADD"
+ labelPlacement="right"
+ (click)="openAddTargetModal()">
+ </svg-icon-label>
+</div>
+<div class="expand-collapse-content">
+ <ul>
+ <li *ngFor="let target of targets; let i = index" class="component-details-panel-large-item"
+ tooltip="{{target.name}}">
+ <span>{{target.name}}</span>
+ <svg-icon-label *ngIf="!isViewOnly"
+ name="trash-o"
+ clickable="true"
+ size="small"
+ class="component-details-panel-item-delete"
+ data-tests-id="delete_target"
+ (click)="deleteTarget(target)"></svg-icon-label>
+ </li>
+ </ul>
+
+ <div *ngIf="targets.length===0" class="component-details-panel-tab-no-data">
+ <div class="component-details-panel-tab-no-data-title">No data to display yet</div>
+ <div class="component-details-panel-tab-no-data-content">Add targets to policy to see targets</div>
+ </div>
+</div>
+
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
new file mode 100644
index 0000000000..cd7ace2b6f
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-targets-tab.component.less
@@ -0,0 +1,12 @@
+/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
new file mode 100644
index 0000000000..b79f4d9e07
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-targets-tab.component.ts
@@ -0,0 +1,145 @@
+/*-
+ * ============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<TargetUiObject>; // UI object to hold all targets with names.
+
+ @Input() policy: PolicyInstance;
+ @Input() topologyTemplate: TopologyTemplate;
+ @Input() isViewOnly: boolean;
+ @Output() isLoading: EventEmitter<boolean> = new EventEmitter<boolean>();
+ @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<TargetUiObject> = 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<TargetUiObject> = _.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<TargetUiObject> {
+ let optionalsTargetsToAdd:Array<TargetUiObject> = [];
+ // 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.component.html b/catalog-ui/src/app/ng2/pages/composition/panel/panel.component.html
new file mode 100644
index 0000000000..430b272ff0
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel.component.html
@@ -0,0 +1,34 @@
+<ng2-composition-panel-header
+ [name]="selectedZoneInstanceName"
+ [topologyTemplate]="topologyTemplate"
+ [selectedZoneInstanceType]="selectedZoneInstanceType"
+ [selectedZoneInstanceId]="selectedZoneInstanceId"
+ [nonCertified]="nonCertified"
+ [isViewOnly]="isViewOnly"
+ [isLoading]="isLoading"
+></ng2-composition-panel-header>
+
+<div class="component-details-panel-tabs">
+ <loader [display]="isLoading" [size]="'large'" [relative]="true" [loaderDelay]="500"></loader>
+
+ <div *ngIf="selectedZoneInstanceType === zoneInstanceType.POLICY">
+ <policy-tabs
+ [topologyTemplate]="topologyTemplate"
+ [selectedZoneInstanceType]="selectedZoneInstanceType"
+ [selectedZoneInstanceId]="selectedZoneInstanceId"
+ [isViewOnly]="isViewOnly"
+ (isLoading)="setIsLoading($event)"
+ ></policy-tabs>
+ </div>
+
+ <div *ngIf="selectedZoneInstanceType === zoneInstanceType.GROUP">
+ <group-tabs
+ [topologyTemplate]="topologyTemplate"
+ [selectedZoneInstanceType]="selectedZoneInstanceType"
+ [selectedZoneInstanceId]="selectedZoneInstanceId"
+ [isViewOnly]="isViewOnly"
+ (isLoading)="setIsLoading($event)"
+ ></group-tabs>
+ </div>
+
+</div>
diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel.component.less b/catalog-ui/src/app/ng2/pages/composition/panel/panel.component.less
new file mode 100644
index 0000000000..1777d54486
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel.component.less
@@ -0,0 +1,11 @@
+/deep/
+.component-details-panel {
+
+ color: #666666;
+ font-family: OpenSans-Regular, sans-serif;
+ font-size: 14px;
+
+ .component-details-panel-tabs {
+
+ }
+}
diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel.component.ts b/catalog-ui/src/app/ng2/pages/composition/panel/panel.component.ts
new file mode 100644
index 0000000000..53599d6366
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel.component.ts
@@ -0,0 +1,60 @@
+/*-
+ * ============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, SimpleChanges, HostBinding } from "@angular/core";
+import { Component as TopologyTemplate, ComponentInstance, IAppMenu } from "app/models";
+import { PolicyInstance } from 'app/models/graph/zones/policy-instance';
+import { TranslateService } from 'app/ng2/shared/translator/translate.service';
+import { ZoneInstanceType } from "app/models/graph/zones/zone-instance";
+import { GroupsService } from "../../../services/groups.service";
+import { PoliciesService } from "../../../services/policies.service";
+import { SdcUiComponents } from "sdc-ui/lib/angular";
+import { IZoneService } from "../../../../models/graph/zones/zone";
+
+@Component({
+ selector: 'ng2-composition-panel',
+ templateUrl: './panel.component.html',
+ styleUrls: ['./panel.component.less'],
+ providers: [TranslateService]
+})
+export class CompositionPanelComponent {
+
+ @Input() topologyTemplate: TopologyTemplate;
+ @Input() selectedZoneInstanceType: ZoneInstanceType;
+ @Input() selectedZoneInstanceId: string;
+ @Input() selectedZoneInstanceName: string;
+ @Input() nonCertified: boolean;
+ @Input() isViewOnly: boolean;
+ @Input() isLoading: boolean;
+
+
+ @HostBinding('class') classes = 'component-details-panel';
+
+ private zoneInstanceType = ZoneInstanceType; // Expose ZoneInstanceType to use in template.
+
+ constructor(){
+ }
+
+ private setIsLoading = (value):void => {
+ this.isLoading = value;
+ }
+
+}
diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel.module.ts b/catalog-ui/src/app/ng2/pages/composition/panel/panel.module.ts
new file mode 100644
index 0000000000..57f6be8b8e
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel.module.ts
@@ -0,0 +1,54 @@
+/*-
+ * ============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 {CompositionPanelComponent} from "./panel.component";
+import {CompositionPanelHeaderModule} from "app/ng2/pages/composition/panel/panel-header/panel-header.module";
+import {GroupTabsModule} from "./panel-tabs/groups/group-tabs.module";
+import {PolicyTabsModule} from "./panel-tabs/policies/policy-tabs.module";
+import {SdcUiComponents} from "sdc-ui/lib/angular";
+import {UiElementsModule} from 'app/ng2/components/ui/ui-elements.module';
+import {AddElementsModule} from "../../../components/ui/modal/add-elements/add-elements.module";
+
+@NgModule({
+ declarations: [
+ CompositionPanelComponent
+ ],
+ imports: [
+ BrowserModule,
+ FormsModule,
+ HttpModule,
+ CompositionPanelHeaderModule,
+ PolicyTabsModule,
+ GroupTabsModule,
+ UiElementsModule,
+ AddElementsModule
+ ],
+ entryComponents: [
+ CompositionPanelComponent
+ ],
+ exports: [],
+ providers: [SdcUiComponents.ModalService]
+})
+export class CompositionPanelModule {
+
+}
diff --git a/catalog-ui/src/app/ng2/pages/connection-wizard/connection-wizard.service.ts b/catalog-ui/src/app/ng2/pages/connection-wizard/connection-wizard.service.ts
index bf5ec4c4f6..af8dcb4956 100644
--- a/catalog-ui/src/app/ng2/pages/connection-wizard/connection-wizard.service.ts
+++ b/catalog-ui/src/app/ng2/pages/connection-wizard/connection-wizard.service.ts
@@ -22,19 +22,6 @@ export class ConnectionWizardService {
// this.selectedCapability = rel
}
-
- // getComponentInstanceIdOfSelectedCapability = (): string => {
- // if(this.selectedMatch.capability){
- // if(this.selectedMatch.isFromTo) {
- // return this.selectedMatch.toNode;
- // } else {
- // return this.selectedMatch.fromNode;
- // }
- // }
- // return '';
- //
- // }
-
getOptionalRequirementsByInstanceUniqueId = (isFromTo: boolean, matchWith?:Capability): Dictionary<Requirement[]> => {
let requirements: Array<Requirement> = [];
_.forEach(this.connectRelationModel.possibleRelations, (match: Match) => {
diff --git a/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.html b/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.html
index 03e9f1fa7e..5142bba383 100644
--- a/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.html
+++ b/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.html
@@ -10,7 +10,7 @@
[searchTerm]="searchQuery"
[selectedPropertyId]="selectedFlatProperty.path"
[propertyNameSearchText]="searchPropertyName"
- [readonly]="isReadonly"
+ [readonly]="isReadonly || resourceIsReadonly"
[isLoading]="loadingProperties || savingChangedData"
[hasDeclareOption]="true"
(propertyChanged)="dataChanged($event)"
@@ -59,7 +59,7 @@
<hierarchy-navigation class="hierarchy-nav"
(updateSelected)="onInstanceSelectedUpdate($event)"
[displayData]="isInputsTabSelected ? []: instancesNavigationData"
- [selectedItem]="selectedInstanceData.uniqueId"
+ [selectedItem]="selectedInstanceData?.uniqueId"
[displayOptions]="hierarchyInstancesDisplayOptions"></hierarchy-navigation>
</div>
</tab>
@@ -79,9 +79,4 @@
</tabs>
</div>
</div>
- <template #saveChangedDataModalContentTemplate>
- <loader [display]="savingChangedData" [size]="'medium'" [relative]="true"></loader>
- Your changes{{isValidChangedData ? '' : ' (invalid)'}} have not been saved.<br>
- Do you want to {{isValidChangedData ? 'save' : 'discard'}} them?
- </template>
</div>
diff --git a/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.ts b/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.ts
index 40818bce78..5a21e86879 100644
--- a/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.ts
+++ b/catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.ts
@@ -25,7 +25,7 @@ import { PropertyFEModel, InstanceFePropertiesMap, InstanceBePropertiesMap, Inst
import { ResourceType } from "app/utils";
import {ComponentServiceNg2} from "../../services/component-services/component.service";
import {ComponentInstanceServiceNg2} from "../../services/component-instance-services/component-instance.service"
-import { InputBEModel, InputFEModel, ComponentInstance, PropertyBEModel, DerivedFEProperty, ResourceInstance, SimpleFlatProperty } from "app/models";
+import { InputBEModel, InputFEModel, ComponentInstance, GroupInstance, PolicyInstance, PropertyBEModel, DerivedFEProperty, SimpleFlatProperty } from "app/models";
import { KeysPipe } from 'app/ng2/pipes/keys.pipe';
import {WorkspaceMode, EVENTS} from "../../../utils/constants";
import {EventListenerService} from "app/services/event-listener-service"
@@ -38,6 +38,11 @@ import {ComponentModeService} from "../../services/component-services/component-
import {ModalService} from "../../services/modal.service";
import {Tabs, Tab} from "../../components/ui/tabs/tabs.component";
import {InputsUtils} from "./services/inputs.utils";
+import { InstanceFeDetails } from "../../../models/instance-fe-details";
+import { SdcUiComponents } from "sdc-ui/lib/angular";
+//import { ModalService as ModalServiceSdcUI} from "sdc-ui/lib/angular/modals/modal.service";
+import { IModalButtonComponent } from "sdc-ui/lib/angular/modals/models/modal-config";
+import { UnsavedChangesComponent } from "app/ng2/components/ui/forms/unsaved-changes/unsaved-changes.component";
@Component({
templateUrl: './properties-assignment.page.component.html',
@@ -47,30 +52,30 @@ export class PropertiesAssignmentComponent {
title = "Properties & Inputs";
component: ComponentData;
- componentInstanceNamesMap: Map<string, string> = new Map<string, string>();//instanceUniqueId, name
+ componentInstanceNamesMap: Map<string, InstanceFeDetails> = new Map<string, InstanceFeDetails>();//instanceUniqueId, {name, iconClass}
propertiesNavigationData = [];
instancesNavigationData = [];
instanceFePropertiesMap:InstanceFePropertiesMap;
inputs: Array<InputFEModel> = [];
- instances: Array<ComponentInstance> = [];
+ instances: Array<ComponentInstance|GroupInstance|PolicyInstance> = [];
searchQuery: string;
propertyStructureHeader: string;
selectedFlatProperty: SimpleFlatProperty = new SimpleFlatProperty();
- selectedInstanceType: string;
- selectedInstanceData: ComponentInstance = new ComponentInstance();
+ selectedInstanceData: ComponentInstance|GroupInstance|PolicyInstance = null;
checkedPropertiesCount: number = 0;
hierarchyPropertiesDisplayOptions:HierarchyDisplayOptions = new HierarchyDisplayOptions('path', 'name', 'childrens');
- hierarchyInstancesDisplayOptions:HierarchyDisplayOptions = new HierarchyDisplayOptions('uniqueId', 'name');
+ hierarchyInstancesDisplayOptions:HierarchyDisplayOptions = new HierarchyDisplayOptions('uniqueId', 'name', 'archived', null, 'iconClass');
displayClearSearch = false;
searchPropertyName:string;
currentMainTab:Tab;
isInputsTabSelected:boolean;
isPropertiesTabSelected:boolean;
isReadonly:boolean;
+ resourceIsReadonly:boolean;
loadingInstances:boolean = false;
loadingInputs:boolean = false;
loadingProperties:boolean = false;
@@ -83,8 +88,7 @@ export class PropertiesAssignmentComponent {
@ViewChild('hierarchyNavTabs') hierarchyNavTabs: Tabs;
@ViewChild('propertyInputTabs') propertyInputTabs: Tabs;
@ViewChild('advanceSearch') advanceSearch: FilterPropertiesAssignmentComponent;
- @ViewChild('saveChangedDataModalContentTemplate') saveChangedDataModalContentTemplateRef: TemplateRef<void>;
-
+
constructor(private propertiesService: PropertiesService,
private hierarchyNavService: HierarchyNavService,
private propertiesUtils:PropertiesUtils,
@@ -97,14 +101,15 @@ export class PropertiesAssignmentComponent {
@Inject("Notification") private Notification:any,
private componentModeService:ComponentModeService,
private ModalService:ModalService,
- private EventListenerService:EventListenerService) {
+ private EventListenerService:EventListenerService,
+ private ModalServiceSdcUI: SdcUiComponents.ModalService) {
this.instanceFePropertiesMap = new InstanceFePropertiesMap();
/* This is the way you can access the component data, please do not use any data except metadata, all other data should be received from the new api calls on the first time
than if the data is already exist, no need to call the api again - Ask orit if you have any questions*/
this.component = _stateParams.component;
- this.EventListenerService.registerObserverCallback(EVENTS.ON_CHECKOUT, this.onCheckout);
+ this.EventListenerService.registerObserverCallback(EVENTS.ON_LIFECYCLE_CHANGE, this.onCheckout);
this.updateViewMode();
this.changedData = [];
@@ -129,13 +134,16 @@ export class PropertiesAssignmentComponent {
}, error => {}); //ignore error
this.componentServiceNg2
- .getComponentResourceInstances(this.component)
+ .getComponentResourcePropertiesData(this.component)
.subscribe(response => {
- this.instances = response.componentInstances;
+ this.instances = [];
+ this.instances.push(...response.componentInstances);
+ this.instances.push(...response.groupInstances);
+ this.instances.push(...response.policies);
_.forEach(this.instances, (instance) => {
this.instancesNavigationData.push(instance);
- this.componentInstanceNamesMap[instance.uniqueId] = instance.name;
+ this.componentInstanceNamesMap[instance.uniqueId] = <InstanceFeDetails>{name: instance.name, iconClass:instance.iconClass, originArchived:instance.originArchived};
});
this.loadingInstances = false;
if (this.instancesNavigationData[0] == undefined) {
@@ -148,17 +156,15 @@ export class PropertiesAssignmentComponent {
// stop if has changed properties
if (this.hasChangedData) {
event.preventDefault();
- this.openChangedDataModal().then((proceed) => {
- if (proceed) {
- this.$state.go(toState, toParams);
- }
- });
+ this.showUnsavedChangesAlert().then(() => {
+ this.$state.go(toState, toParams);
+ }, () => {});
}
});
};
ngOnDestroy() {
- this.EventListenerService.unRegisterObserver(EVENTS.ON_CHECKOUT);
+ this.EventListenerService.unRegisterObserver(EVENTS.ON_LIFECYCLE_CHANGE);
this.stateChangeStartUnregister();
}
@@ -178,47 +184,64 @@ export class PropertiesAssignmentComponent {
}
- onInstanceSelectedUpdate = (resourceInstance: ResourceInstance) => {
- console.log("==>" + this.constructor.name + ": onInstanceSelectedUpdate");
-
+ onInstanceSelectedUpdate = (instance: ComponentInstance|GroupInstance|PolicyInstance) => {
// stop if has changed properties
if (this.hasChangedData) {
- this.openChangedDataModal().then((proceed) => {
- if (proceed) {
- this.onInstanceSelectedUpdate(resourceInstance);
- }
+ this.showUnsavedChangesAlert().then((resolve)=> {
+ this.changeSelectedInstance(instance)
+ }, (reject) => {
});
return;
}
+ this.changeSelectedInstance(instance);
+ };
- let instanceBePropertiesMap: InstanceBePropertiesMap = new InstanceBePropertiesMap();
- this.selectedInstanceData = resourceInstance;
- this.selectedInstanceType = resourceInstance.originType;
-
+ changeSelectedInstance = (instance: ComponentInstance|GroupInstance|PolicyInstance) => {
+ this.selectedInstanceData = instance;
this.loadingProperties = true;
- if (this.isInput(resourceInstance.originType)) {
+ if (instance instanceof ComponentInstance) {
+ let instanceBePropertiesMap: InstanceBePropertiesMap = new InstanceBePropertiesMap();
+ if (this.isInput(instance.originType)) {
+ this.componentInstanceServiceNg2
+ .getComponentInstanceInputs(this.component, instance)
+ .subscribe(response => {
+ instanceBePropertiesMap[instance.uniqueId] = response;
+ this.processInstancePropertiesResponse(instanceBePropertiesMap, true);
+ this.loadingProperties = false;
+ }, error => {
+ }); //ignore error
+ } else {
+ this.componentInstanceServiceNg2
+ .getComponentInstanceProperties(this.component, instance.uniqueId)
+ .subscribe(response => {
+ instanceBePropertiesMap[instance.uniqueId] = response;
+ this.processInstancePropertiesResponse(instanceBePropertiesMap, false);
+ this.loadingProperties = false;
+ }, error => {
+ }); //ignore error
+ }
+
+ this.resourceIsReadonly = (instance.componentName === "vnfConfiguration");
+ } else if (instance instanceof GroupInstance) {
+ let instanceBePropertiesMap: InstanceBePropertiesMap = new InstanceBePropertiesMap();
this.componentInstanceServiceNg2
- .getComponentInstanceInputs(this.component, resourceInstance)
- .subscribe(response => {
- instanceBePropertiesMap[resourceInstance.uniqueId] = response;
- this.processInstancePropertiesResponse(instanceBePropertiesMap, true);
+ .getComponentGroupInstanceProperties(this.component, this.selectedInstanceData.uniqueId)
+ .subscribe((response) => {
+ instanceBePropertiesMap[instance.uniqueId] = response;
+ this.processInstancePropertiesResponse(instanceBePropertiesMap, false);
this.loadingProperties = false;
-
- }, error => {
- }); //ignore error
- } else {
+ });
+ } else if (instance instanceof PolicyInstance) {
+ let instanceBePropertiesMap: InstanceBePropertiesMap = new InstanceBePropertiesMap();
this.componentInstanceServiceNg2
- .getComponentInstanceProperties(this.component, resourceInstance.uniqueId)
- .subscribe(response => {
- instanceBePropertiesMap[resourceInstance.uniqueId] = response;
+ .getComponentPolicyInstanceProperties(this.component, this.selectedInstanceData.uniqueId)
+ .subscribe((response) => {
+ instanceBePropertiesMap[instance.uniqueId] = response;
this.processInstancePropertiesResponse(instanceBePropertiesMap, false);
this.loadingProperties = false;
- }, error => {
- }); //ignore error
- }
-
- if (resourceInstance.componentName === "vnfConfiguration") {
- this.isReadonly = true;
+ });
+ } else {
+ this.loadingProperties = false;
}
if (this.searchPropertyName) {
@@ -289,7 +312,7 @@ export class PropertiesAssignmentComponent {
this.propertyStructureHeader = null;
// Build hirarchy tree for the navigation and update propertiesNavigationData with it.
- if(this.selectedInstanceData.originType !== ResourceType.VF) {
+ if (!(this.selectedInstanceData instanceof ComponentInstance) || this.selectedInstanceData.originType !== ResourceType.VF) {
let simpleFlatProperty:Array<SimpleFlatProperty>;
if (property instanceof PropertyFEModel) {
simpleFlatProperty = this.hierarchyNavService.getSimplePropertiesTree(property, instanceName);
@@ -322,14 +345,11 @@ export class PropertiesAssignmentComponent {
tabChanged = (event) => {
// stop if has changed properties
if (this.hasChangedData) {
- this.openChangedDataModal().then((proceed) => {
- if (proceed) {
- this.propertyInputTabs.selectTab(this.propertyInputTabs.tabs.find((tab) => tab.title === event.title));
- }
- });
-
- // return to show the current tab
this.propertyInputTabs.triggerTabChange(this.currentMainTab.title);
+ this.showUnsavedChangesAlert().then((proceed) => {
+ this.propertyInputTabs.selectTab(this.propertyInputTabs.tabs.find((tab) => tab.title === event.title));
+ }, ()=> {
+ });
return;
}
@@ -347,21 +367,28 @@ export class PropertiesAssignmentComponent {
declareProperties = (): void => {
console.log("==>" + this.constructor.name + ": declareProperties");
- let selectedProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
- let selectedInputs: InstanceBePropertiesMap = new InstanceBePropertiesMap();
+ let selectedComponentInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
+ let selectedGroupInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
+ let selectedPolicyInstancesProperties: InstanceBePropertiesMap = new InstanceBePropertiesMap();
+ let selectedComponentInstancesInputs: InstanceBePropertiesMap = new InstanceBePropertiesMap();
let instancesIds = new KeysPipe().transform(this.instanceFePropertiesMap, []);
angular.forEach(instancesIds, (instanceId: string): void => {
- let selectedInstanceData: ResourceInstance = this.instances.find(instance => instance.uniqueId == instanceId);
- let originType: string = (selectedInstanceData) ? selectedInstanceData.originType : this.selectedInstanceType;
- if (!this.isInput(originType)) {
- selectedProperties[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
- } else {
- selectedInputs[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
+ let selectedInstanceData: any = this.instances.find(instance => instance.uniqueId == instanceId);
+ if (selectedInstanceData instanceof ComponentInstance) {
+ if (!this.isInput(selectedInstanceData.originType)) {
+ selectedComponentInstancesProperties[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
+ } else {
+ selectedComponentInstancesInputs[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
+ }
+ } else if (selectedInstanceData instanceof GroupInstance) {
+ selectedGroupInstancesProperties[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
+ } else if (selectedInstanceData instanceof PolicyInstance) {
+ selectedPolicyInstancesProperties[instanceId] = this.propertiesService.getCheckedProperties(this.instanceFePropertiesMap[instanceId]);
}
});
- let inputsToCreate: InstancePropertiesAPIMap = new InstancePropertiesAPIMap(selectedInputs, selectedProperties);
+ let inputsToCreate: InstancePropertiesAPIMap = new InstancePropertiesAPIMap(selectedComponentInstancesInputs, selectedComponentInstancesProperties, selectedGroupInstancesProperties, selectedPolicyInstancesProperties);
this.componentServiceNg2
.createInput(this.component, inputsToCreate)
@@ -399,20 +426,46 @@ export class PropertiesAssignmentComponent {
return propBE;
});
- if (this.isInput(this.selectedInstanceData.originType)) {
+ if (this.selectedInstanceData instanceof ComponentInstance) {
+ if (this.isInput(this.selectedInstanceData.originType)) {
+ request = this.componentInstanceServiceNg2
+ .updateInstanceInputs(this.component, this.selectedInstanceData.uniqueId, changedProperties);
+ handleSuccess = (response) => {
+ // reset each changed property with new value and remove it from changed properties list
+ response.forEach((resInput) => {
+ const changedProp = <PropertyFEModel>this.changedData.shift();
+ this.propertiesUtils.resetPropertyValue(changedProp, resInput.value);
+ });
+ console.log('updated instance inputs:', response);
+ };
+ } else {
+ request = this.componentInstanceServiceNg2
+ .updateInstanceProperties(this.component, this.selectedInstanceData.uniqueId, changedProperties)
+ handleSuccess = (response) => {
+ // reset each changed property with new value and remove it from changed properties list
+ response.forEach((resProp) => {
+ const changedProp = <PropertyFEModel>this.changedData.shift();
+ this.propertiesUtils.resetPropertyValue(changedProp, resProp.value);
+ });
+ resolve(response);
+ console.log("updated instance properties: ", response);
+ };
+ }
+ } else if (this.selectedInstanceData instanceof GroupInstance) {
request = this.componentInstanceServiceNg2
- .updateInstanceInputs(this.component, this.selectedInstanceData.uniqueId, changedProperties);
+ .updateComponentGroupInstanceProperties(this.component, this.selectedInstanceData.uniqueId, changedProperties);
handleSuccess = (response) => {
// reset each changed property with new value and remove it from changed properties list
- response.forEach((resInput) => {
+ response.forEach((resProp) => {
const changedProp = <PropertyFEModel>this.changedData.shift();
- this.propertiesUtils.resetPropertyValue(changedProp, resInput.value);
+ this.propertiesUtils.resetPropertyValue(changedProp, resProp.value);
});
- console.log('updated instance inputs:', response);
+ resolve(response);
+ console.log("updated group instance properties: ", response);
};
- } else {
+ } else if (this.selectedInstanceData instanceof PolicyInstance) {
request = this.componentInstanceServiceNg2
- .updateInstanceProperties(this.component, this.selectedInstanceData.uniqueId, changedProperties)
+ .updateComponentPolicyInstanceProperties(this.component, this.selectedInstanceData.uniqueId, changedProperties);
handleSuccess = (response) => {
// reset each changed property with new value and remove it from changed properties list
response.forEach((resProp) => {
@@ -420,7 +473,7 @@ export class PropertiesAssignmentComponent {
this.propertiesUtils.resetPropertyValue(changedProp, resProp.value);
});
resolve(response);
- console.log("updated instance properties: ", response);
+ console.log("updated policy instance properties: ", response);
};
}
} else if (this.isInputsTabSelected) {
@@ -484,66 +537,59 @@ export class PropertiesAssignmentComponent {
const curHasChangedData:boolean = (this.changedData.length > 0);
if (curHasChangedData !== this.hasChangedData) {
this.hasChangedData = curHasChangedData;
- this.$scope.$emit('setWorkspaceTopBarActive', !this.hasChangedData);
- }
+ if(this.hasChangedData) {
+ this.EventListenerService.notifyObservers(EVENTS.ON_WORKSPACE_UNSAVED_CHANGES, this.hasChangedData, this.showUnsavedChangesAlert);
+ } else {
+ this.EventListenerService.notifyObservers(EVENTS.ON_WORKSPACE_UNSAVED_CHANGES, false);
+ }
+ }
return this.hasChangedData;
};
- doSaveChangedData = ():void => {
+ doSaveChangedData = (onSuccessFunction?:Function, onError?:Function):void => {
this.saveChangedData().then(
() => {
this.Notification.success({
message: 'Successfully saved changes',
title: 'Saved'
});
+ if(onSuccessFunction) onSuccessFunction();
},
() => {
this.Notification.error({
message: 'Failed to save changes!',
title: 'Failure'
});
+ if(onError) onError();
}
);
};
- openChangedDataModal = ():Promise<boolean> => {
- let modalTitle;
+ showUnsavedChangesAlert = ():Promise<any> => {
+ let modalTitle:string;
if (this.isPropertiesTabSelected) {
modalTitle = `Unsaved properties for ${this.selectedInstanceData.name}`;
} else if (this.isInputsTabSelected) {
modalTitle = `Unsaved inputs for ${this.component.name}`;
}
- return new Promise<boolean>((resolve) => {
- const modal = this.ModalService.createCustomModal(new ModalModel(
- 'sm',
- modalTitle,
- null,
- [
- new ButtonModel('Cancel', 'outline grey', () => {
- modal.instance.close();
- resolve(false);
- }),
- new ButtonModel('Discard', 'outline blue', () => {
- this.reverseChangedData();
- modal.instance.close();
- resolve(true);
- }),
- new ButtonModel('Save', 'blue', () => {
- this.saveChangedData().then(() => {
- modal.instance.close();
- resolve(true);
- }, () => {
- modal.instance.close();
- resolve(false);
- });
- }, () => !this.isValidChangedData)
- ]
- ));
- this.ModalService.addDynamicTemplateToModal(modal, this.saveChangedDataModalContentTemplateRef);
- modal.instance.open();
+ return new Promise<any>((resolve, reject) => {
+ const modal = this.ModalServiceSdcUI.openCustomModal(
+ {
+ title: modalTitle,
+ size: 'sm',
+ type: 'custom',
+ testId: "id",
+
+ buttons: [
+ {id: 'cancelButton', text: 'Cancel', type: 'secondary', size: 'xsm', closeModal: true, callback: () => reject()},
+ {id: 'discardButton', text: 'Discard', type: 'secondary', size: 'xsm', closeModal: true, callback: () => { this.reverseChangedData(); resolve()}},
+ {id: 'saveButton', text: 'Save', type: 'primary', size: 'xsm', closeModal: true, disabled: !this.isValidChangedData, callback: () => this.doSaveChangedData(resolve, reject)}
+ ] as IModalButtonComponent[]
+ }, UnsavedChangesComponent, {isValidChangedData: this.isValidChangedData});
});
- };
+
+ }
updatePropertyValueAfterDeclare = (input: InputFEModel) => {
if (this.instanceFePropertiesMap[input.instanceUniqueId]) {
@@ -567,7 +613,16 @@ export class PropertiesAssignmentComponent {
this.propertyInputTabs.setTabIndication('Inputs', numInputs);
};
+ resetUnsavedChangesForInput = (input:InputFEModel) => {
+ this.inputsUtils.resetInputDefaultValue(input, input.defaultValue);
+ this.changedData = this.changedData.filter((changedItem) => changedItem.uniqueId !== input.uniqueId);
+ this.updateHasChangedData();
+ }
+
deleteInput = (input: InputFEModel) => {
+ //reset any unsaved changes to the input before deleting it
+ this.resetUnsavedChangesForInput(input);
+
console.log("==>" + this.constructor.name + ": deleteInput");
let inputToDelete = new InputBEModel(input);
@@ -577,7 +632,7 @@ export class PropertiesAssignmentComponent {
this.inputs = this.inputs.filter(input => input.uniqueId !== response.uniqueId);
//Reload the whole instance for now - TODO: CHANGE THIS after the BE starts returning properties within the response, use commented code below instead!
- this.onInstanceSelectedUpdate(this.selectedInstanceData);
+ this.changeSelectedInstance(this.selectedInstanceData);
// let instanceFeProperties = this.instanceFePropertiesMap[this.getInstanceUniqueId(input.instanceName)];
// if (instanceFeProperties) {
diff --git a/catalog-ui/src/app/ng2/pages/service-path-creator/link-row/link-row.component.html b/catalog-ui/src/app/ng2/pages/service-path-creator/link-row/link-row.component.html
index bbbf6ae694..e029b7f1fa 100644
--- a/catalog-ui/src/app/ng2/pages/service-path-creator/link-row/link-row.component.html
+++ b/catalog-ui/src/app/ng2/pages/service-path-creator/link-row/link-row.component.html
@@ -1,5 +1,45 @@
-<ui-element-dropdown data-tests-id="linkSrc" [readonly]="!link.isFirst || (link.isFirst && !link.canEdit)" class="cell link-selector" [values]="source" [(value)]="link.fromNode" (valueChange)="onSourceSelected($event)"></ui-element-dropdown>
-<ui-element-dropdown data-tests-id="linkSrcCP" [readonly]="!link.isFirst || (link.isFirst && !link.canEdit)" class="cell link-selector" [values]="srcCP" [(value)]="link.fromCP" (valueChange)="onSrcCPSelected($event)"></ui-element-dropdown>
-<ui-element-dropdown data-tests-id="linkTarget" [readonly]="!link.canEdit" class="cell link-selector" [values]="target" [(value)]="link.toNode" (valueChange)="onTargetSelected($event)"></ui-element-dropdown>
-<ui-element-dropdown data-tests-id="linkTargetCP" [readonly]="!link.canEdit" class="cell link-selector" [values]="targetCP" [(value)]="link.toCP" (valueChange)="onTargetCPSelected($event)"></ui-element-dropdown>
-<div class="cell remove" data-tests-id="removeLnk"><span *ngIf="link.canRemove" class="sprite-new delete-item-icon" (click)="removeRow()"></span></div> \ No newline at end of file
+<ui-element-dropdown
+ data-tests-id="linkSrc"
+ [readonly]="!link.isFirst || (link.isFirst && !link.canEdit)"
+ class="cell link-selector"
+ [values]="source"
+ [(value)]="link.fromNode"
+ (valueChange)="onSourceSelected($event)">
+</ui-element-dropdown>
+
+<ui-element-dropdown
+ data-tests-id="linkSrcCP"
+ [readonly]="!link.isFirst || (link.isFirst && !link.canEdit)"
+ class="cell link-selector"
+ [values]="srcCP"
+ [(value)]="link.fromCP"
+ (valueChange)="onSrcCPSelected($event)">
+</ui-element-dropdown>
+
+<ui-element-dropdown
+ data-tests-id="linkTarget"
+ [readonly]="!link.canEdit"
+ class="cell link-selector"
+ [values]="target"
+ [(value)]="link.toNode"
+ (valueChange)="onTargetSelected($event)">
+</ui-element-dropdown>
+
+<ui-element-dropdown
+ data-tests-id="linkTargetCP"
+ [readonly]="!link.canEdit"
+ class="cell link-selector"
+ [values]="targetCP"
+ [(value)]="link.toCP"
+ (valueChange)="onTargetCPSelected($event)">
+</ui-element-dropdown>
+
+<div
+ class="cell remove"
+ data-tests-id="removeLnk">
+ <span
+ *ngIf="link.canRemove"
+ class="sprite-new delete-item-icon"
+ (click)="removeRow()">
+ </span>
+</div>
diff --git a/catalog-ui/src/app/ng2/pages/service-path-creator/link-row/link-row.component.ts b/catalog-ui/src/app/ng2/pages/service-path-creator/link-row/link-row.component.ts
index 16433242d6..e4fc1d4522 100644
--- a/catalog-ui/src/app/ng2/pages/service-path-creator/link-row/link-row.component.ts
+++ b/catalog-ui/src/app/ng2/pages/service-path-creator/link-row/link-row.component.ts
@@ -14,7 +14,7 @@ export class LinkRowComponent {
@Input() data:Array<ServicePathMapItem>;
@Input() link:Link;
@Input() removeRow:Function;
- source:Array<DropdownValue> = [];
+ source: Array<DropdownValue> = [];
target: Array<DropdownValue> = [];
srcCP: Array<DropdownValue> = [];
targetCP: Array<DropdownValue> = [];
@@ -32,11 +32,9 @@ export class LinkRowComponent {
if (!srcCPOptions) { return; }
this.srcCP = this.convertValuesToDropDownOptions(srcCPOptions);
if (this.link.fromCP) {
- let targetOptions = this.findOptions(srcCPOptions, this.link.fromCP);
- if (!targetOptions) { return; }
- this.target = this.convertValuesToDropDownOptions(targetOptions);
+ this.target = this.convertValuesToDropDownOptions(data);
if (this.link.toNode) {
- let targetCPOptions = this.findOptions(targetOptions, this.link.toNode);
+ let targetCPOptions = this.findOptions(data, this.link.toNode);
if (!targetCPOptions) { return; }
this.targetCP = this.convertValuesToDropDownOptions(targetCPOptions);
}
@@ -45,7 +43,7 @@ export class LinkRowComponent {
}
private findOptions(items: Array<ServicePathMapItem>, nodeOrCPId: string) {
- let item = items.find((dataItem)=> nodeOrCPId === dataItem.id);
+ let item = _.find(items, (dataItem) => nodeOrCPId === dataItem.id);
if (item && item.data && item.data.options) {
return item.data.options;
}
@@ -53,12 +51,12 @@ export class LinkRowComponent {
return null;
}
- private convertValuesToDropDownOptions(values: Array<ServicePathMapItem>) : Array<DropdownValue> {
- let result = [];
+ private convertValuesToDropDownOptions(values: Array<ServicePathMapItem>): Array<DropdownValue> {
+ let result:Array<DropdownValue> = [];
for (let i = 0; i < values.length ; i++) {
result[result.length] = new DropdownValue(values[i].id, values[i].data.name);
}
- return result;
+ return result.sort((a, b) => a.label.localeCompare(b.label));
}
onSourceSelected(id) {
@@ -75,10 +73,9 @@ export class LinkRowComponent {
onSrcCPSelected (id) {
if (id) {
- let srcCPData = this.data.find((dataItem)=> this.link.fromNode === dataItem.id).data;
- let srcCPOptions = srcCPData.options;
- let targetOptions = this.findOptions(srcCPOptions, id);
- this.target = this.convertValuesToDropDownOptions(targetOptions);
+ let srcCPOptions = this.findOptions(this.data, this.link.fromNode);
+ let srcCPData = srcCPOptions.find(option => id === option.id).data;
+ this.target = this.convertValuesToDropDownOptions(this.data);
this.link.fromCPOriginId = srcCPData.ownerId;
this.link.toNode = '';
this.link.toCP = '';
@@ -89,9 +86,7 @@ export class LinkRowComponent {
onTargetSelected(id) {
if (id) {
- let srcCPOptions = this.findOptions(this.data, this.link.fromNode);
- let targetOptions = this.findOptions(srcCPOptions, this.link.fromCP);
- let targetCPOptions = this.findOptions(targetOptions, id);
+ let targetCPOptions = this.findOptions(this.data, id);
this.targetCP = this.convertValuesToDropDownOptions(targetCPOptions);
this.link.toCP = '';
}
@@ -100,11 +95,9 @@ export class LinkRowComponent {
onTargetCPSelected(id) {
if (id) {
- let srcCPOptions = this.findOptions(this.data, this.link.fromNode);
- let targetOptions = this.findOptions(srcCPOptions, this.link.fromCP);
- let targetCPOptions = this.findOptions(targetOptions, this.link.toNode);
- let targetCPDataObj = targetCPOptions.find((dataItem)=> id === dataItem.id).data;
+ let targetCPOptions = this.findOptions(this.data, this.link.toNode);
+ let targetCPDataObj = targetCPOptions.find(option => id === option.id).data;
this.link.toCPOriginId = targetCPDataObj.ownerId;
}
}
-} \ No newline at end of file
+}
diff --git a/catalog-ui/src/app/ng2/pages/service-path-creator/service-path-creator.component.html b/catalog-ui/src/app/ng2/pages/service-path-creator/service-path-creator.component.html
index 96cd83eef6..76c5c53290 100644
--- a/catalog-ui/src/app/ng2/pages/service-path-creator/service-path-creator.component.html
+++ b/catalog-ui/src/app/ng2/pages/service-path-creator/service-path-creator.component.html
@@ -1,27 +1,24 @@
<div class="service-path-creator">
<form class="w-sdc-form">
<div class="i-sdc-form-item" >
- <label class="i-sdc-form-label required">Path Name</label>
- <!-- <ui-element-input type="text" name="pathName" [value]="pathName" ></ui-element-input> -->
- <input type="text" data-tests-id="pathName" name="pathName" [(ngModel)]="forwardingPath.name" [attr.maxLength]="100" /> <!-- TODO - make unique -->
+ <label class="i-sdc-form-label required">Flow Name</label>
+ <input type="text" data-tests-id="pathName" name="pathName" [(ngModel)]="forwardingPath.name" [attr.maxLength]="200" />
</div>
<div class="side-by-side">
<div class="i-sdc-form-item" >
<label class="i-sdc-form-label">Protocol</label>
- <!-- <ui-element-input type="text" name="protocol" [value]="protocol" ></ui-element-input> -->
- <input type="text" data-tests-id="pathProtocol" name="protocol" [(ngModel)]="forwardingPath.protocol" [attr.maxLength]="100" />
+ <input type="text" data-tests-id="pathProtocol" name="protocol" [(ngModel)]="forwardingPath.protocol" [attr.maxLength]="200" />
</div>
<div class="i-sdc-form-item" >
<label class="i-sdc-form-label">Destination Port Numbers</label>
- <!-- <ui-element-input type="text" name="portNumbers" [value]="portNumbers" ></ui-element-input> -->
- <input type="text" data-tests-id="pathPortNumbers" name="portNumbers" [(ngModel)]="forwardingPath.destinationPortNumber" pattern="[0-9,]*" /> <!-- TODO - validate delimiter -->
+ <input type="text" data-tests-id="pathPortNumbers" name="portNumbers" [(ngModel)]="forwardingPath.destinationPortNumber" pattern="[0-9,]*" />
</div>
</div>
<div class="separator-buttons">
<span class="based-on-title">Based On</span>
- <a (click)="addRow()" [ngClass]="{'disabled':!isExtendAllowed()}" data-tests-id="extendPathlnk">Extend Path</a>
+ <a (click)="addRow()" [ngClass]="{'disabled':!isExtendAllowed()}" data-tests-id="extendPathlnk">Extend Flow</a>
</div>
<div class="generic-table">
diff --git a/catalog-ui/src/app/ng2/pages/service-path-creator/service-path-creator.component.ts b/catalog-ui/src/app/ng2/pages/service-path-creator/service-path-creator.component.ts
index dac41a37bc..bffb1c5e7e 100644
--- a/catalog-ui/src/app/ng2/pages/service-path-creator/service-path-creator.component.ts
+++ b/catalog-ui/src/app/ng2/pages/service-path-creator/service-path-creator.component.ts
@@ -73,12 +73,11 @@ export class ServicePathCreatorComponent {
this.forwardingPath.uniqueId = forwardingPath.uniqueId;
this.links = [];
_.forEach(forwardingPath.pathElements.listToscaDataDefinition, (link:ForwardingPathLink) => {
- this.links[this.links.length] = new Link( link, false, false, false);
+ this.links[this.links.length] = new Link(link, false, false, false);
});
- this.links[this.links.length -1].canEdit = true;
- this.links[this.links.length -1].canRemove = true;
+ this.links[this.links.length - 1].canEdit = true;
+ this.links[this.links.length - 1].canRemove = true;
this.links[0].isFirst = true;
-
}
}
@@ -98,7 +97,18 @@ export class ServicePathCreatorComponent {
addRow() {
this.disableRows();
- this.links[this.links.length] = new Link( new ForwardingPathLink(this.links[this.links.length-1].toNode,this.links[this.links.length-1].toCP,'','',this.links[this.links.length-1].toCPOriginId,''),true, true, false);
+ this.links[this.links.length] = new Link(
+ new ForwardingPathLink(this.links[this.links.length-1].toNode,
+ this.links[this.links.length-1].toCP,
+ '',
+ '',
+ this.links[this.links.length-1].toCPOriginId,
+ ''
+ ),
+ true,
+ true,
+ false
+ );
}
disableRows() {
diff --git a/catalog-ui/src/app/ng2/pages/service-paths-list/service-paths-list.component.html b/catalog-ui/src/app/ng2/pages/service-paths-list/service-paths-list.component.html
index 8a31c76998..39c41916a2 100644
--- a/catalog-ui/src/app/ng2/pages/service-paths-list/service-paths-list.component.html
+++ b/catalog-ui/src/app/ng2/pages/service-paths-list/service-paths-list.component.html
@@ -1,5 +1,5 @@
<div class="service-path-list">
- <div class="add-path-link"><a (click)="onAddServicePath()" data-tests-id="add-service-path-lnk" >+ Add Path</a></div>
+ <div class="add-path-link" *ngIf="!isViewOnly"><a (click)="onAddServicePath()" data-tests-id="add-service-path-lnk" >+ Add Flow</a></div>
<div class="generic-table table-container" >
<div class="header-row">
<div class="cell header-cell" *ngFor="let header of headers">
@@ -10,11 +10,11 @@
<div class="cell" data-tests-id="path-name" >{{path.name}}</div>
<div class="cell path-action-buttons">
<span class="sprite-new update-component-icon" (click)="onEditServicePath(path.uniqueId)" data-tests-id="update-service-path-btn" ></span>
- <span class="sprite-new delete-item-icon" (click)="deletePath(path.uniqueId)" data-tests-id="delete-service-path-btn"></span>
+ <span class="sprite-new delete-item-icon" *ngIf="!isViewOnly" (click)="deletePath(path.uniqueId)" data-tests-id="delete-service-path-btn"></span>
</div>
</div>
<div *ngIf="paths && paths.length === 0" class="no-row-text" >
- No paths have been added yet.
+ No flows have been added yet.
</div>
</div>
diff --git a/catalog-ui/src/app/ng2/pages/service-paths-list/service-paths-list.component.less b/catalog-ui/src/app/ng2/pages/service-paths-list/service-paths-list.component.less
index aff597fd85..291119f58c 100644
--- a/catalog-ui/src/app/ng2/pages/service-paths-list/service-paths-list.component.less
+++ b/catalog-ui/src/app/ng2/pages/service-paths-list/service-paths-list.component.less
@@ -18,4 +18,7 @@
.sprite-new {
cursor: pointer;
}
+ & > span:only-child {
+ margin: auto;
+}
} \ No newline at end of file
diff --git a/catalog-ui/src/app/ng2/pages/service-paths-list/service-paths-list.component.ts b/catalog-ui/src/app/ng2/pages/service-paths-list/service-paths-list.component.ts
index 04083e8685..1625ab4b66 100644
--- a/catalog-ui/src/app/ng2/pages/service-paths-list/service-paths-list.component.ts
+++ b/catalog-ui/src/app/ng2/pages/service-paths-list/service-paths-list.component.ts
@@ -38,9 +38,10 @@ export default class ServicePathsListComponent {
input:any;
onAddServicePath: Function;
onEditServicePath: Function;
+ isViewOnly: boolean;
constructor(private serviceService:ServiceServiceNg2) {
- this.headers = ['Path Name','Actions'];
+ this.headers = ['Flow Name','Actions'];
}
ngOnInit() {
@@ -52,6 +53,7 @@ export default class ServicePathsListComponent {
});
this.onAddServicePath = this.input.onCreateServicePath;
this.onEditServicePath = this.input.onEditServicePath;
+ this.isViewOnly = this.input.isViewOnly;
}
deletePath = (id:string):void => {