re base code
Change-Id: I12a5ca14a6d8a87e9316b9ff362eb131105f98a5
Issue-ID: SDC-1566
Signed-off-by: Michael Lando <ml636r@att.com>
diff --git a/catalog-ui/src/app/ng2/app.module.ts b/catalog-ui/src/app/ng2/app.module.ts
index c3cd060..c949a73 100644
--- a/catalog-ui/src/app/ng2/app.module.ts
+++ b/catalog-ui/src/app/ng2/app.module.ts
@@ -18,51 +18,61 @@
* ============LICENSE_END=========================================================
*/
-import {BrowserModule} from '@angular/platform-browser';
-import {NgModule, APP_INITIALIZER} from '@angular/core';
-import {FormsModule} from '@angular/forms';
-import {forwardRef} from '@angular/core';
-import {AppComponent} from './app.component';
-import {UpgradeAdapter} from '@angular/upgrade';
-import {UpgradeModule} from '@angular/upgrade/static';
-import {PropertiesAssignmentModule} from './pages/properties-assignment/properties-assignment.module';
+import { BrowserModule } from '@angular/platform-browser';
+import { NgModule, APP_INITIALIZER } from '@angular/core';
+import { FormsModule } from '@angular/forms';
+import { forwardRef } from '@angular/core';
+import { AppComponent } from './app.component';
+import { UpgradeAdapter } from '@angular/upgrade';
+import { UpgradeModule } from '@angular/upgrade/static';
+import { SdcUiComponentsModule, SdcUiComponents } from "sdc-ui/lib/angular";
+import { PropertiesAssignmentModule } from './pages/properties-assignment/properties-assignment.module';
import {
DataTypesServiceProvider, SharingServiceProvider, CookieServiceProvider, StateServiceFactory,
StateParamsServiceFactory, CacheServiceProvider, EventListenerServiceProvider, ScopeServiceFactory,
- NotificationServiceProvider
+ NotificationServiceProvider, ComponentFactoryProvider
} from "./utils/ng1-upgraded-provider";
-import {ConfigService} from "./services/config.service";
-import {HttpModule} from '@angular/http';
-import {HttpService} from './services/http.service';
-import {AuthenticationService} from './services/authentication.service';
-import {Cookie2Service} from "./services/cookie.service";
-import {ComponentServiceNg2} from "./services/component-services/component.service";
-import {ComponentServiceFactoryNg2} from "./services/component-services/component.service.factory";
-import {ServiceServiceNg2} from "./services/component-services/service.service";
-import {ComponentInstanceServiceNg2} from "./services/component-instance-services/component-instance.service";
-import {ModalService} from "./services/modal.service";
-import {UiElementsModule} from "./components/ui/ui-elements.module";
-import {ConnectionWizardModule} from "./pages/connection-wizard/connection-wizard.module";
+import { ConfigService } from "./services/config.service";
+import { HttpModule } from '@angular/http';
+import { HttpService } from './services/http.service';
+import { AuthenticationService } from './services/authentication.service';
+import { Cookie2Service } from "./services/cookie.service";
+import { ComponentServiceNg2 } from "./services/component-services/component.service";
+import { ComponentServiceFactoryNg2 } from "./services/component-services/component.service.factory";
+import { ServiceServiceNg2 } from "./services/component-services/service.service";
+import { ComponentInstanceServiceNg2 } from "./services/component-instance-services/component-instance.service";
+import { ModalService } from "./services/modal.service";
+import { UiElementsModule } from "./components/ui/ui-elements.module";
+import { ConnectionWizardModule } from "./pages/connection-wizard/connection-wizard.module";
import {InterfaceOperationModule} from "./pages/interface-operation/interface-operation.module";
import {OperationCreatorModule} from "./pages/interface-operation/operation-creator/operation-creator.module";
-import {LayoutModule} from "./components/layout/layout.module";
-import {UserService} from "./services/user.service";
-import {PoliciesService} from "./services/policies.service";
-import {DynamicComponentService} from "./services/dynamic-component.service";
-import {SdcConfig} from "./config/sdc-config.config";
+import { LayoutModule } from "./components/layout/layout.module";
+import { UserService } from "./services/user.service";
+import { DynamicComponentService } from "./services/dynamic-component.service";
+import { SdcConfig } from "./config/sdc-config.config";
+import { SdcMenu } from "./config/sdc-menu.config";
import { TranslateModule } from "./shared/translator/translate.module";
import { TranslationServiceConfig } from "./config/translation.service.config";
-import {ServicePathCreatorModule} from './pages/service-path-creator/service-path-creator.module';
-import {ServicePathsListModule} from './pages/service-paths-list/service-paths-list.module';
+import { MultilineEllipsisModule } from "./shared/multiline-ellipsis/multiline-ellipsis.module";
+import { ServicePathCreatorModule } from './pages/service-path-creator/service-path-creator.module';
+import { ServicePathsListModule } from './pages/service-paths-list/service-paths-list.module';
+import { ServicePathModule } from 'app/ng2/components/logic/service-path/service-path.module';
+import { ServicePathSelectorModule } from 'app/ng2/components/logic/service-path-selector/service-path-selector.module';
+import { CompositionPanelModule } from 'app/ng2/pages/composition/panel/panel.module';
+import { WindowRef } from "./services/window.service";
+import {ArchiveService} from "./services/archive.service";
+import { ModalsHandlerProvider } from './utils/ng1-upgraded-provider';
import {PluginFrameModule} from "./components/ui/plugin/plugin-frame.module";
import {PluginsService} from "./services/plugins.service";
import {EventBusService} from "./services/event-bus.service";
-import {ServicePathModule} from 'app/ng2/components/logic/service-path/service-path.module';
-import {ServicePathSelectorModule} from 'app/ng2/components/logic/service-path-selector/service-path-selector.module';
+import {GroupsService} from "./services/groups.service";
+import {PoliciesService} from "./services/policies.service";
+import {AutomatedUpgradeService} from "./pages/automated-upgrade/automated-upgrade.service";
+import {AutomatedUpgradeModule} from "./pages/automated-upgrade/automated-upgrade.module";
export const upgradeAdapter = new UpgradeAdapter(forwardRef(() => AppModule));
-export function configServiceFactory(config:ConfigService) {
+export function configServiceFactory(config: ConfigService) {
return () => {
return Promise.all([
config.loadValidationConfiguration(),
@@ -83,8 +93,11 @@
HttpModule,
LayoutModule,
TranslateModule,
+ MultilineEllipsisModule,
UiElementsModule,
-
+ CompositionPanelModule,
+ SdcUiComponentsModule,
+ AutomatedUpgradeModule,
//We need to import them here since we use them in angular1
ConnectionWizardModule,
PropertiesAssignmentModule,
@@ -97,10 +110,15 @@
ServicePathSelectorModule
],
exports: [],
- entryComponents: [],
+ entryComponents: [
+ // *** sdc-ui components to be used as downgraded:
+ // SdcUiComponents.ButtonComponent
+ ],
providers: [
+ WindowRef,
DataTypesServiceProvider,
SharingServiceProvider,
+ ComponentFactoryProvider,
CookieServiceProvider,
StateServiceFactory,
StateParamsServiceFactory,
@@ -108,6 +126,7 @@
CacheServiceProvider,
EventListenerServiceProvider,
NotificationServiceProvider,
+ ModalsHandlerProvider,
AuthenticationService,
Cookie2Service,
ConfigService,
@@ -115,14 +134,18 @@
ComponentServiceFactoryNg2,
ModalService,
ServiceServiceNg2,
+ AutomatedUpgradeService,
HttpService,
UserService,
PoliciesService,
+ GroupsService,
DynamicComponentService,
SdcConfig,
+ SdcMenu,
ComponentInstanceServiceNg2,
TranslationServiceConfig,
PluginsService,
+ ArchiveService,
EventBusService,
{
provide: APP_INITIALIZER,
@@ -130,13 +153,13 @@
deps: [ConfigService],
multi: true
},
- ],
+ ],
bootstrap: [AppComponent]
})
export class AppModule {
+ constructor(public upgrade: UpgradeModule, public eventBusService:EventBusService) {
- constructor(public upgrade:UpgradeModule, eventBusService:EventBusService) {
}
}
diff --git a/catalog-ui/src/app/ng2/components/layout/top-nav/top-nav.component.html b/catalog-ui/src/app/ng2/components/layout/top-nav/top-nav.component.html
index 55c4bf0..78f3111 100644
--- a/catalog-ui/src/app/ng2/components/layout/top-nav/top-nav.component.html
+++ b/catalog-ui/src/app/ng2/components/layout/top-nav/top-nav.component.html
@@ -20,7 +20,7 @@
<li [ngClass]="{'selected': $last }">
<a (click)="menuItemClick(groupItem, groupItem.menuItems[groupItem.selectedIndex])"
[attr.data-tests-id]="'breadcrumbs-button-' + $index">
- {{groupItem.menuItems[groupItem.selectedIndex].text}}
+ {{groupItem.menuItems[groupItem.selectedIndex]?.text}}
</a>
</li>
<li class="triangle-dropdown"
diff --git a/catalog-ui/src/app/ng2/components/layout/top-nav/top-nav.component.ts b/catalog-ui/src/app/ng2/components/layout/top-nav/top-nav.component.ts
index a0b6b2b..881a916 100644
--- a/catalog-ui/src/app/ng2/components/layout/top-nav/top-nav.component.ts
+++ b/catalog-ui/src/app/ng2/components/layout/top-nav/top-nav.component.ts
@@ -41,6 +41,8 @@
@Input() public hideSearch:boolean;
@Input() public searchTerm:string;
@Input() public notificationIconCallback:Function;
+ @Input() public unsavedChanges: boolean;
+ @Input() public unsavedChangesCallback: (completeCallback:Function)=> Promise<any>;
@Output() public searchTermChange:EventEmitter<string> = new EventEmitter<string>();
emitSearchTerm(event:string) {
this.searchTermChange.emit(event);
@@ -80,17 +82,21 @@
return true;
});
- //if it's a different state , checking previous state param
+ //if it's a different state
if (result === -1) {
- this.topLvlMenu.menuItems.forEach((item:MenuItem, index:number)=> {
- if (item.state === this.$state.params['previousState']) {
- result = index;
- }
- });
- }
+ //if in 'workspace' - checking previous state param
+ if (this.$state.includes('workspace')) {
+ // if previous state is 'dashboard' or 'catalog', then select it - otherwise, use 'catalog' as default for 'workspace'
+ const selectedStateName = (['dashboard', 'catalog'].indexOf(this.$state.params['previousState']) !== -1)
+ ? this.$state.params['previousState']
+ : 'catalog';
+ result = this.topLvlMenu.menuItems.findIndex((item:MenuItem) => item.state === selectedStateName);
+ }
- if (result === -1) {
- result = 0;
+ //if yet, none is selected, then select the first as default
+ if (result === -1) {
+ result = 0;
+ }
}
return result;
@@ -151,8 +157,21 @@
}
menuItemClick(itemGroup:MenuItemGroup, item:MenuItem) {
- itemGroup.itemClick = false;
+ let onSuccessFunction = () => {
+ this.navigate(itemGroup, item);
+ }
+ if (this.unsavedChanges && this.unsavedChangesCallback){
+ this.unsavedChangesCallback(onSuccessFunction).then((onSuccess)=> {
+ this.navigate(itemGroup, item);
+ }, (onReject) => {});
+ } else {
+ this.navigate(itemGroup, item);
+ }
+ }
+
+ navigate(itemGroup:MenuItemGroup, item:MenuItem) {
+ itemGroup.itemClick = false;
let onSuccess = ():void => {
itemGroup.selectedIndex = itemGroup.menuItems.indexOf(item);
};
@@ -165,4 +184,5 @@
this[item.action](item.state, item.params).then(onSuccess, onFailed);
}
}
+
}
diff --git a/catalog-ui/src/app/ng2/components/logic/hierarchy-navigtion/hierarchy-display-options.ts b/catalog-ui/src/app/ng2/components/logic/hierarchy-navigtion/hierarchy-display-options.ts
index c8d4566..36257ca 100644
--- a/catalog-ui/src/app/ng2/components/logic/hierarchy-navigtion/hierarchy-display-options.ts
+++ b/catalog-ui/src/app/ng2/components/logic/hierarchy-navigtion/hierarchy-display-options.ts
@@ -23,10 +23,16 @@
valueProperty: string;
childrenProperty: string;
searchText:string;
- constructor(idProperty:string, valueProperty:string, childrenProperty?:string, searchText?:string) {
+ archived:boolean;
+
+ iconProperty: string;
+ constructor(idProperty:string, valueProperty:string, childrenProperty?:string, searchText?:string, iconProperty?:string, archived?:boolean) {
+
this.idProperty = idProperty;
this.valueProperty = valueProperty;
this.childrenProperty = childrenProperty;
this.searchText = searchText;
+ this.archived = archived;
+ this.iconProperty = iconProperty;
}
}
diff --git a/catalog-ui/src/app/ng2/components/logic/hierarchy-navigtion/hierarchy-navigation.component.html b/catalog-ui/src/app/ng2/components/logic/hierarchy-navigtion/hierarchy-navigation.component.html
index c3f9e5a..aa60337 100644
--- a/catalog-ui/src/app/ng2/components/logic/hierarchy-navigtion/hierarchy-navigation.component.html
+++ b/catalog-ui/src/app/ng2/components/logic/hierarchy-navigtion/hierarchy-navigation.component.html
@@ -1,7 +1,12 @@
<div class="navigation-wrapper">
<div class="node-item" *ngFor="let item of displayData" (click)="onClick($event, item)">
<div class="node-data-wrapper" [ngClass]="{'selected': selectedItem && selectedItem === item[displayOptions.idProperty]}">
- <span class="node-data" [ngClass]="{'mark':item[displayOptions.valueProperty] === displayOptions.searchText}" [attr.data-tests-id]="item[displayOptions.valueProperty]">{{item[displayOptions.valueProperty]}}</span>
+ <span class="node-data" [ngClass]="{'mark':item[displayOptions.valueProperty] === displayOptions.searchText}" [attr.data-tests-id]="item[displayOptions.valueProperty]">
+
+ <span *ngIf="displayOptions.iconProperty" [ngClass]="['node-data-icon', item[displayOptions.iconProperty], 'small']"></span>
+ {{item[displayOptions.valueProperty]}}
+ <span class="sprite-new archive-label" *ngIf="item.originArchived"></span>
+ </span>
</div>
<div class="children-node" *ngIf="item[displayOptions.childrenProperty]">
<hierarchy-navigation class="children-hierarchy" [displayData]="item[displayOptions.childrenProperty]"
diff --git a/catalog-ui/src/app/ng2/components/logic/hierarchy-navigtion/hierarchy-navigation.component.less b/catalog-ui/src/app/ng2/components/logic/hierarchy-navigtion/hierarchy-navigation.component.less
index 4befa2c..33ffb49 100644
--- a/catalog-ui/src/app/ng2/components/logic/hierarchy-navigtion/hierarchy-navigation.component.less
+++ b/catalog-ui/src/app/ng2/components/logic/hierarchy-navigtion/hierarchy-navigation.component.less
@@ -1,3 +1,5 @@
+@import './../../../../../assets/styles/mixins.less';
+
.navigation-wrapper {
text-align: left;
}
@@ -30,6 +32,25 @@
.node-data {
margin-left: 10px;
margin-right: 10px;
+ align-items: center;
+ display: block;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ max-width: 300px;
+ .archive-label{
+ margin-left: 5px;
+ }
+}
+
+.node-data-icon {
+ vertical-align: middle;
+ margin-right: 7px;
+
+ &.defaulticon.small {
+ background-color: #999;
+ border-radius: 14px;
+ }
}
.node-data-wrapper.selected {
@@ -50,3 +71,20 @@
+.icon-group {
+ .square-icon();
+ background-color: @main_color_a;
+
+ &::before {
+ content: "G";
+ }
+}
+.icon-policy {
+ .square-icon();
+ background-color: @main_color_r;
+
+ &::before {
+ content: "P";
+ }
+}
+
diff --git a/catalog-ui/src/app/ng2/components/logic/inputs-table/inputs-table.component.html b/catalog-ui/src/app/ng2/components/logic/inputs-table/inputs-table.component.html
index b7cde7e..daffc9e 100644
--- a/catalog-ui/src/app/ng2/components/logic/inputs-table/inputs-table.component.html
+++ b/catalog-ui/src/app/ng2/components/logic/inputs-table/inputs-table.component.html
@@ -17,8 +17,8 @@
tooltip="{{input.description}}" tooltipDelay="0"></span>
</div>
<div class="table-cell col3">
- <div class="inner-cell-div" tooltip="{{instanceNamesMap[input.instanceUniqueId]}}">
- <span>{{instanceNamesMap[input.instanceUniqueId]}}</span>
+ <div class="inner-cell-div" tooltip="{{instanceNamesMap[input.instanceUniqueId]?.name}}">
+ <span>{{instanceNamesMap[input.instanceUniqueId]?.name}}</span>
</div>
</div>
<div class="table-cell col2">
@@ -34,7 +34,8 @@
[type]="input.type"
[name]="input.name"
(elementChanged)="onInputChanged(input, $event)"
- [readonly]="readonly">
+ [readonly]="readonly"
+ [testId]="'input-' + input.name">
</dynamic-element>
<div class="delete-button-container">
<span *ngIf="input.instanceUniqueId && !readonly" class="sprite-new delete-btn" (click)="openDeleteModal(input)" data-tests-id="delete-input-button"></span>
diff --git a/catalog-ui/src/app/ng2/components/logic/inputs-table/inputs-table.component.less b/catalog-ui/src/app/ng2/components/logic/inputs-table/inputs-table.component.less
index d709f3f..5fbb62f 100644
--- a/catalog-ui/src/app/ng2/components/logic/inputs-table/inputs-table.component.less
+++ b/catalog-ui/src/app/ng2/components/logic/inputs-table/inputs-table.component.less
@@ -85,8 +85,8 @@
border-right:#d2d2d2 solid 1px;
}
&.col1 {
- flex: 1 0 210px;
- max-width:210px;
+ flex: 1 0 120px;
+ max-width:120px;
display: flex;
justify-content: space-between;
@@ -112,14 +112,7 @@
}
&.valueCol {
- flex: 1 0 auto;
- min-width: 350px;
- display: flex;
- justify-content: flex-end;
- padding: 0px;
- align-items: center;
-
- .value-input {
+ .value-input {
flex: 1;
border: none;
background-color: inherit;
@@ -142,7 +135,7 @@
padding: 0px;
.delete-button-container {
- padding: 3px 5px 0 0 ;
+ padding: 0 8px 0 0 ;
}
}
}
diff --git a/catalog-ui/src/app/ng2/components/logic/inputs-table/inputs-table.component.ts b/catalog-ui/src/app/ng2/components/logic/inputs-table/inputs-table.component.ts
index ebecbc9..0c7fc2a 100644
--- a/catalog-ui/src/app/ng2/components/logic/inputs-table/inputs-table.component.ts
+++ b/catalog-ui/src/app/ng2/components/logic/inputs-table/inputs-table.component.ts
@@ -24,6 +24,7 @@
import {Component, Input, Output, EventEmitter} from "@angular/core";
import {InputFEModel} from "app/models";
import {ModalService} from "../../../services/modal.service";
+import { InstanceFeDetails } from "app/models/instance-fe-details";
@Component({
selector: 'inputs-table',
@@ -33,7 +34,7 @@
export class InputsTableComponent {
@Input() inputs: Array<InputFEModel>;
- @Input() instanceNamesMap: Map<string, string>;
+ @Input() instanceNamesMap: Map<string, InstanceFeDetails>;
@Input() readonly:boolean;
@Input() isLoading:boolean;
@Output() inputChanged: EventEmitter<any> = new EventEmitter<any>();
diff --git a/catalog-ui/src/app/ng2/components/logic/properties-table/dynamic-property/dynamic-property.component.html b/catalog-ui/src/app/ng2/components/logic/properties-table/dynamic-property/dynamic-property.component.html
index 4805875..b5ae7a8 100644
--- a/catalog-ui/src/app/ng2/components/logic/properties-table/dynamic-property/dynamic-property.component.html
+++ b/catalog-ui/src/app/ng2/components/logic/properties-table/dynamic-property/dynamic-property.component.html
@@ -19,6 +19,7 @@
[name]="property.name"
(elementChanged)="mapKeyChanged.emit($event.value)"
[readonly]="readonly"
+ [testId]="'prop-key-' + propertyTestsId"
></dynamic-element>
</div>
</ng-container>
@@ -27,12 +28,13 @@
<div class="table-cell">
<dynamic-element class="value-input"
pattern="validationUtils.getValidationPattern(property.type)"
- [value]="property.valueObj"
+ [value]="property.isDeclared ? property.value : property.valueObj"
[type]="property.isDeclared ? 'string' : property.type"
[name]="property.name"
[path]="property.propertiesName"
(elementChanged)="onElementChanged($event)"
[readonly]="readonly || property.isDeclared || property.isDisabled"
+ [testId]="'prop-' + propertyTestsId"
></dynamic-element>
</div>
</ng-container>
@@ -45,9 +47,9 @@
</ng-container>
<!-- ICONS: add, delete, and expand -->
<ng-container *ngIf="!property.isDeclared">
- <a *ngIf="(propType == derivedPropertyTypes.LIST || propType == derivedPropertyTypes.MAP) && !property.isChildOfListOrMap" class="property-icon add-item" (click)="createNewChildProperty();" [ngClass]="{'disabled':readonly || preventInsertItem(property)}">Add value to list</a>
- <span *ngIf="property.isChildOfListOrMap" (click)="deleteItem.emit(property);" class="property-icon sprite-new delete-item-icon" [ngClass]="{'disabled':readonly}"></span>
- <span *ngIf="!isPropertyFEModel && (propType == derivedPropertyTypes.COMPLEX || ((propType == derivedPropertyTypes.LIST || propType == derivedPropertyTypes.MAP) && hasChildren))" (click)="expandChildById(propPath)" class="property-icon sprite-new round-expand-icon" [class.open]="expandedChildId.indexOf(propPath) == 0"></span>
+ <a *ngIf="(propType == derivedPropertyTypes.LIST || propType == derivedPropertyTypes.MAP) && !property.isChildOfListOrMap" class="property-icon add-item" (click)="createNewChildProperty();" [ngClass]="{'disabled':readonly || preventInsertItem(property)}" [attr.data-tests-id]="'add-to-list-' + propertyTestsId">Add value to list</a>
+ <span *ngIf="property.isChildOfListOrMap" (click)="deleteItem.emit(property);" class="property-icon sprite-new delete-item-icon" [ngClass]="{'disabled':readonly}" [attr.data-tests-id]="'delete-from-list-' + propertyTestsId"></span>
+ <span *ngIf="!isPropertyFEModel && (propType == derivedPropertyTypes.COMPLEX || ((propType == derivedPropertyTypes.LIST || propType == derivedPropertyTypes.MAP) && hasChildren))" (click)="expandChildById(propPath)" class="property-icon sprite-new round-expand-icon" [class.open]="expandedChildId.indexOf(propPath) == 0" [attr.data-tests-id]="'expand-' + propertyTestsId"></span>
</ng-container>
</div>
@@ -59,6 +61,7 @@
[hasDeclareOption]="hasDeclareOption"
[canBeDeclared]="hasDeclareOption && prop.canBeDeclared"
[property]="prop"
+ [rootProperty]="rootProperty || property"
[expandedChildId]="expandedChildId"
[propertyNameSearchText]="propertyNameSearchText"
[readonly]="readonly"
diff --git a/catalog-ui/src/app/ng2/components/logic/properties-table/dynamic-property/dynamic-property.component.ts b/catalog-ui/src/app/ng2/components/logic/properties-table/dynamic-property/dynamic-property.component.ts
index 6f7e57b..6e19c95 100644
--- a/catalog-ui/src/app/ng2/components/logic/properties-table/dynamic-property/dynamic-property.component.ts
+++ b/catalog-ui/src/app/ng2/components/logic/properties-table/dynamic-property/dynamic-property.component.ts
@@ -41,6 +41,7 @@
propPath: string;
isPropertyFEModel: boolean;
nestedLevel: number;
+ propertyTestsId: string;
@Input() canBeDeclared: boolean;
@Input() property: PropertyFEModel | DerivedFEProperty;
@@ -50,6 +51,7 @@
@Input() readonly: boolean;
@Input() hasChildren: boolean;
@Input() hasDeclareOption:boolean;
+ @Input() rootProperty: PropertyFEModel;
@Output('propertyChanged') emitter: EventEmitter<void> = new EventEmitter<void>();
@Output() expandChild: EventEmitter<string> = new EventEmitter<string>();
@@ -69,6 +71,8 @@
this.propType = this.property.derivedDataType;
this.propPath = (this.property instanceof PropertyFEModel) ? this.property.name : this.property.propertiesName;
this.nestedLevel = (this.property.propertiesName.match(/#/g) || []).length;
+ this.rootProperty = (this.rootProperty) ? this.rootProperty : <PropertyFEModel>this.property;
+ this.propertyTestsId = this.getPropertyTestsId();
}
ngDoCheck() {
@@ -105,6 +109,10 @@
}).length > 1;
}
+ getPropertyTestsId = () => {
+ return [this.rootProperty.name].concat(this.rootProperty.getParentNamesArray(this.property.propertiesName, [], true)).join('.');
+ };
+
onElementChanged = (event: IUiElementChangeEvent) => {
this.property.updateValueObj(event.value, event.isValid);
this.emitter.emit();
diff --git a/catalog-ui/src/app/ng2/components/logic/properties-table/properties-table.component.html b/catalog-ui/src/app/ng2/components/logic/properties-table/properties-table.component.html
index ecfa7e7..b574b55 100644
--- a/catalog-ui/src/app/ng2/components/logic/properties-table/properties-table.component.html
+++ b/catalog-ui/src/app/ng2/components/logic/properties-table/properties-table.component.html
@@ -9,8 +9,14 @@
<div class="table-body" [ngClass]="{'view-mode': readonly}">
<div class="no-data" *ngIf="!fePropertiesMap || !(fePropertiesMap | keys).length">No data to display</div>
- <ng-container *ngFor="let instanceId of fePropertiesMap | keys; trackBy:instanceId">
- <div class="table-rows-header white-sub-header" *ngIf="feInstanceNamesMap">{{feInstanceNamesMap[instanceId]}}</div>
+ <ng-container *ngFor="let instanceId of fePropertiesMap | keys; trackBy:vspId">
+ <div class="table-rows-header white-sub-header" *ngIf="feInstanceNamesMap">
+
+
+ <span [ngClass]="['prop-instance-icon', feInstanceNamesMap[instanceId].iconClass, 'small']"></span>
+ {{feInstanceNamesMap[instanceId].name}}
+ <div class="sprite-new archive-label" *ngIf="feInstanceNamesMap[instanceId].originArchived == true" ></div>
+ </div>
<div class="table-row"
*ngFor="let property of fePropertiesMap[instanceId] | searchFilter:'name':searchTerm; trackBy:property?.name"
@@ -22,8 +28,8 @@
<checkbox *ngIf="hasDeclareOption" [(checked)]="property.isSelected"
[disabled]="property.isDisabled || property.isDeclared || readonly"
(checkedChange)="propertyChecked(property)" [attr.data-tests-id]="property.name"></checkbox>
- <div class="inner-cell-div" tooltip="{{property.name}}">
- <span>{{property.name}}</span>
+ <div class="inner-cell-div-multiline" tooltip="{{property.name}}">
+ <multiline-ellipsis className="table-cell-multiline-ellipsis" [lines]="2">{{property.name}}</multiline-ellipsis>
</div>
</div>
<span *ngIf="property.description" class="property-description-icon sprite-new show-desc" tooltip="{{property.description}}" tooltipDelay="0"></span>
diff --git a/catalog-ui/src/app/ng2/components/logic/properties-table/properties-table.component.less b/catalog-ui/src/app/ng2/components/logic/properties-table/properties-table.component.less
index 20da0b6..72f67e4 100644
--- a/catalog-ui/src/app/ng2/components/logic/properties-table/properties-table.component.less
+++ b/catalog-ui/src/app/ng2/components/logic/properties-table/properties-table.component.less
@@ -1,4 +1,4 @@
-@import './../../../../../assets/styles/variables.less';
+@import './../../../../../assets/styles/mixins.less';
@import '../../../../../assets/styles/sprite';
@smaller-screen: ~"only screen and (max-width: 1580px)";
@@ -12,13 +12,16 @@
text-align:left;
- .inner-cell-div{
- max-width: 100%;
+ .inner-cell-div {
text-overflow: ellipsis;
overflow: hidden;
height: 20px;
}
+ .inner-cell-div-multiline {
+ max-width: 100%;
+ }
+
.table-header {
display: flex;
flex-direction:row;
@@ -36,6 +39,11 @@
.table-rows-header {
border: #d2d2d2 solid 1px;
border-top:none;
+ display: flex;
+ align-items: center;
+ .archive-label{
+ margin-left: 10px;
+ }
}
.table-body {
@@ -120,7 +128,7 @@
.property-description-icon {
float: right;
margin-top: 4px;
- margin-left: 5px;
+ margin-left: 15px;
flex: 0 0 auto;
}
}
@@ -177,4 +185,53 @@
}
}
+ .table-row {
+ /deep/ .table-cell-multiline-ellipsis .multiline-ellipsis-dots {
+ background: linear-gradient(to right, transparent 0%, #ffffff 80%);
+ padding-left: 1em;
+ }
+
+ &.selected /deep/ .table-cell-multiline-ellipsis .multiline-ellipsis-dots {
+ background: linear-gradient(to right, transparent 0%, #e6f6fb 80%);
+ padding-left: 1em;
+ }
+
+ &.readonly /deep/ .table-cell-multiline-ellipsis .multiline-ellipsis-dots {
+ background: linear-gradient(to right, transparent 0%, #f8f8f8 80%);
+ padding-left: 1em;
+ }
+
+ &:hover:not(.selected) /deep/ .table-cell-multiline-ellipsis .multiline-ellipsis-dots {
+ background: linear-gradient(to right, transparent 0%, #f8f8f8 80%);
+ padding-left: 1em;
+ }
+ }
+
+ .prop-instance-icon {
+ vertical-align: middle;
+ margin-right: 7px;
+ &.defaulticon.small {
+ background-color: @main_color_q;
+ border-radius:14px;
+ }
+ // square icons
+
+ &.icon-group {
+ .square-icon();
+ background-color: @main_color_a;
+
+ &::before {
+ content: "G";
+ }
+ }
+ &.icon-policy {
+ .square-icon();
+ background-color: @main_color_r;
+
+ &::before {
+ content: "P";
+ }
+ }
+
+ }
}
diff --git a/catalog-ui/src/app/ng2/components/logic/properties-table/properties-table.component.ts b/catalog-ui/src/app/ng2/components/logic/properties-table/properties-table.component.ts
index 093fae1..da1fb82 100644
--- a/catalog-ui/src/app/ng2/components/logic/properties-table/properties-table.component.ts
+++ b/catalog-ui/src/app/ng2/components/logic/properties-table/properties-table.component.ts
@@ -21,6 +21,7 @@
import { Component, Input, Output, EventEmitter} from "@angular/core";
import {PropertyFEModel, DerivedFEProperty, InstanceFePropertiesMap} from "app/models";
import {PropertiesService} from "../../../services/properties.service";
+import { InstanceFeDetails } from "../../../../models/instance-fe-details";
@Component({
selector: 'properties-table',
@@ -30,7 +31,7 @@
export class PropertiesTableComponent {
@Input() fePropertiesMap: InstanceFePropertiesMap;
- @Input() feInstanceNamesMap: Map<string, string>;
+ @Input() feInstanceNamesMap: Map<string, InstanceFeDetails>;
@Input() selectedPropertyId: string;
@Input() propertyNameSearchText:string;
@Input() searchTerm:string;
diff --git a/catalog-ui/src/app/ng2/components/logic/properties-table/property-table.module.ts b/catalog-ui/src/app/ng2/components/logic/properties-table/property-table.module.ts
index 91f3348..91baaf1 100644
--- a/catalog-ui/src/app/ng2/components/logic/properties-table/property-table.module.ts
+++ b/catalog-ui/src/app/ng2/components/logic/properties-table/property-table.module.ts
@@ -8,6 +8,7 @@
import {FilterChildPropertiesPipe} from "./pipes/filterChildProperties.pipe";
import {GlobalPipesModule} from "../../../pipes/global-pipes.module";
import {PropertiesService} from "../../../services/properties.service";
+import {MultilineEllipsisModule} from "../../../shared/multiline-ellipsis/multiline-ellipsis.module";
@NgModule({
imports: [
@@ -15,7 +16,8 @@
HttpModule,
CommonModule,
GlobalPipesModule,
- UiElementsModule
+ UiElementsModule,
+ MultilineEllipsisModule
],
declarations: [
FilterChildPropertiesPipe,
diff --git a/catalog-ui/src/app/ng2/components/logic/select-requirement-or-capability/select-requirement-or-capability.component.html b/catalog-ui/src/app/ng2/components/logic/select-requirement-or-capability/select-requirement-or-capability.component.html
index 6e0f93f..9d570f0 100644
--- a/catalog-ui/src/app/ng2/components/logic/select-requirement-or-capability/select-requirement-or-capability.component.html
+++ b/catalog-ui/src/app/ng2/components/logic/select-requirement-or-capability/select-requirement-or-capability.component.html
@@ -9,7 +9,7 @@
</radio-buttons>
<label class="select-type-label">Select type:</label>
<div class="select-type">
- <ui-element-dropdown [values]="types" [(value)]="selectedType" (valueChange)="onTypeSelected($event)"></ui-element-dropdown>
+ <ui-element-dropdown [values]="types" [(value)]="selectedType" (valueChange)="onTypeSelected($event)" testId="select"></ui-element-dropdown>
</div>
<div class="table-and-list-container">
diff --git a/catalog-ui/src/app/ng2/components/logic/service-path-selector/service-path-selector.component.html b/catalog-ui/src/app/ng2/components/logic/service-path-selector/service-path-selector.component.html
index 72e0835..af7a470 100644
--- a/catalog-ui/src/app/ng2/components/logic/service-path-selector/service-path-selector.component.html
+++ b/catalog-ui/src/app/ng2/components/logic/service-path-selector/service-path-selector.component.html
@@ -1,5 +1,5 @@
<div class="service-path-selector">
- <label>Service Paths:</label>
+ <label>Service Flows:</label>
<ui-element-dropdown
class="path-dropdown"
data-tests-id="service-path-selector"
diff --git a/catalog-ui/src/app/ng2/components/logic/service-path-selector/service-path-selector.component.ts b/catalog-ui/src/app/ng2/components/logic/service-path-selector/service-path-selector.component.ts
index be9966a..e09001f 100644
--- a/catalog-ui/src/app/ng2/components/logic/service-path-selector/service-path-selector.component.ts
+++ b/catalog-ui/src/app/ng2/components/logic/service-path-selector/service-path-selector.component.ts
@@ -1,4 +1,3 @@
-import * as _ from "lodash";
import {Component, Input, KeyValueDiffer, IterableDiffers, KeyValueDiffers, DoCheck} from '@angular/core';
import {Service} from "app/models/components/service";
import {TranslateService} from "app/ng2/shared/translator/translate.service";
diff --git a/catalog-ui/src/app/ng2/components/logic/service-path/service-path.component.html b/catalog-ui/src/app/ng2/components/logic/service-path/service-path.component.html
index ff7902e..75f0642 100644
--- a/catalog-ui/src/app/ng2/components/logic/service-path/service-path.component.html
+++ b/catalog-ui/src/app/ng2/components/logic/service-path/service-path.component.html
@@ -1,22 +1,15 @@
<div class='service-path'>
<button class='zoom-icons create-path-button' data-tests-id="pathsMenuBtn" (click)="showServicePathMenu = !showServicePathMenu">...</button>
- <div class="service-path-menu"
- *ngIf="showServicePathMenu" >
+ <div class="service-path-menu" *ngIf="showServicePathMenu">
<div >
<ul>
- <li><div class="hand" (click)="onCreateServicePath()" data-tests-id="createPathMenuItem">
- Create Service Path
+ <li *ngIf='!isViewOnly'><div class="hand" (click)="onCreateServicePath()" data-tests-id="createPathMenuItem">
+ Create Service Flow
</div></li>
<li><div class="hand" (click)="onListServicePath()" data-tests-id="pathsListMenuItem">
- Service Paths List
+ Service Flows List
</div></li>
</ul>
</div>
</div>
- <!-- TODO - ask Orit about positioning issues and styling issues -->
- <!--
- <menu-list [open]="showServicePathMenu" [position]="menuPos" >
- <menu-item [action]="onCreateServicePath">Create Path</menu-item>
- <menu-item [action]="onListServicePath">Paths' List</menu-item>
- </menu-list> -->
</div>
\ No newline at end of file
diff --git a/catalog-ui/src/app/ng2/components/logic/service-path/service-path.component.ts b/catalog-ui/src/app/ng2/components/logic/service-path/service-path.component.ts
index 4a6209f..d66c5f0 100644
--- a/catalog-ui/src/app/ng2/components/logic/service-path/service-path.component.ts
+++ b/catalog-ui/src/app/ng2/components/logic/service-path/service-path.component.ts
@@ -39,6 +39,7 @@
@Input() service: Service;
@Input() onCreate: Function;
@Input() onSave: Function;
+ @Input() isViewOnly:boolean;
constructor(private ModalServiceNg2: ModalService) {}
@@ -46,7 +47,7 @@
this.showServicePathMenu = false;
let cancelButton: ButtonModel = new ButtonModel('Cancel', 'outline white', this.ModalServiceNg2.closeCurrentModal);
let saveButton: ButtonModel = new ButtonModel('Create', 'blue', this.createPath, this.getDisabled );
- let modalModel: ModalModel = new ModalModel('l', 'Create Service Path', '', [saveButton, cancelButton], 'standard', true);
+ let modalModel: ModalModel = new ModalModel('l', 'Create Service Flow', '', [saveButton, cancelButton], 'standard', true);
this.modalInstance = this.ModalServiceNg2.createCustomModal(modalModel);
this.ModalServiceNg2.addDynamicContentToModal(this.modalInstance, ServicePathCreatorComponent, {service: this.service});
this.modalInstance.instance.open();
@@ -55,10 +56,10 @@
onListServicePath = ():void => {
this.showServicePathMenu = false;
let cancelButton: ButtonModel = new ButtonModel('Close', 'outline white', this.ModalServiceNg2.closeCurrentModal);
- let modalModel: ModalModel = new ModalModel('md', 'Service Paths List','', [cancelButton], 'standard', true);
+ let modalModel: ModalModel = new ModalModel('md', 'Service Flows List','', [cancelButton], 'standard', true);
this.modalInstance = this.ModalServiceNg2.createCustomModal(modalModel);
this.ModalServiceNg2.addDynamicContentToModal(this.modalInstance, ServicePathsListComponent, {service: this.service,
- onCreateServicePath: this.onCreateServicePath, onEditServicePath: this.onEditServicePath});
+ onCreateServicePath: this.onCreateServicePath, onEditServicePath: this.onEditServicePath, isViewOnly: this.isViewOnly});
this.modalInstance.instance.open();
};
@@ -70,14 +71,14 @@
onEditServicePath = (id:string):void => {
let cancelButton: ButtonModel = new ButtonModel('Cancel', 'outline white', this.ModalServiceNg2.closeCurrentModal);
let saveButton: ButtonModel = new ButtonModel('Save', 'blue', this.createPath, this.getDisabled );
- let modalModel: ModalModel = new ModalModel('l', 'Edit Path', '', [saveButton, cancelButton]);
+ let modalModel: ModalModel = new ModalModel('l', 'Edit Path', '', [saveButton, cancelButton], 'standard', true);
this.modalInstance = this.ModalServiceNg2.createCustomModal(modalModel);
this.ModalServiceNg2.addDynamicContentToModal(this.modalInstance, ServicePathCreatorComponent, {service: this.service, pathId: id});
this.modalInstance.instance.open();
};
getDisabled = ():boolean => {
- return !this.modalInstance.instance.dynamicContent.instance.checkFormValidForSubmit();
+ return this.isViewOnly || !this.modalInstance.instance.dynamicContent.instance.checkFormValidForSubmit();
};
}
diff --git a/catalog-ui/src/app/ng2/components/ui/canvas-zone/zone-container.component.html b/catalog-ui/src/app/ng2/components/ui/canvas-zone/zone-container.component.html
index e279e3f..981efbb 100644
--- a/catalog-ui/src/app/ng2/components/ui/canvas-zone/zone-container.component.html
+++ b/catalog-ui/src/app/ng2/components/ui/canvas-zone/zone-container.component.html
@@ -1,11 +1,11 @@
-<div class="sdc-canvas-zone {{class}}-zone" [class.minimized]="minifyZone" [class.hidden]="!showZone">
- <div class="sdc-canvas-zone__header" (click)="unminifyZone()" >
+<div class="sdc-canvas-zone {{class}}-zone" [class.minimized]="minimized" [class.hidden]="!visible" (click)="backgroundClicked()">
+ <div class="sdc-canvas-zone__header" (click)="unminifyZone(); $event.stopPropagation();" >
<div class="sdc-canvas-zone__title">{{title}}
<span class="sdc-canvas-zone__counter">{{count}}</span>
</div>
<span class="sdc-canvas-zone__state-button">–</span>
</div>
- <div class="sdc-canvas-zone__container">
+ <div class="sdc-canvas-zone__container" #scrollDiv >
<ng-content></ng-content>
</div>
</div>
\ No newline at end of file
diff --git a/catalog-ui/src/app/ng2/components/ui/canvas-zone/zone-container.component.less b/catalog-ui/src/app/ng2/components/ui/canvas-zone/zone-container.component.less
index 3e77c5c..02880a9 100644
--- a/catalog-ui/src/app/ng2/components/ui/canvas-zone/zone-container.component.less
+++ b/catalog-ui/src/app/ng2/components/ui/canvas-zone/zone-container.component.less
@@ -1,5 +1,5 @@
.sdc-canvas-zone {
- width: 280px;
+ width: 285px;
max-height:186px;
display:flex;
flex-direction:column;
diff --git a/catalog-ui/src/app/ng2/components/ui/canvas-zone/zone-container.component.ts b/catalog-ui/src/app/ng2/components/ui/canvas-zone/zone-container.component.ts
index 7e60cb3..4059ad6 100644
--- a/catalog-ui/src/app/ng2/components/ui/canvas-zone/zone-container.component.ts
+++ b/catalog-ui/src/app/ng2/components/ui/canvas-zone/zone-container.component.ts
@@ -1,6 +1,5 @@
-import { Component, Input, Output, ViewEncapsulation, EventEmitter } from '@angular/core';
-import { EventListenerService } from 'app/services';
-import { GRAPH_EVENTS } from 'app/utils';
+import { Component, Input, Output, ViewEncapsulation, EventEmitter, OnInit } from '@angular/core';
+import { ZoneInstanceType } from '../../../../models/graph/zones/zone-instance';
@Component({
selector: 'zone-container',
@@ -9,17 +8,28 @@
encapsulation: ViewEncapsulation.None
})
-export class ZoneContainerComponent {
+export class ZoneContainerComponent implements OnInit {
@Input() title:string;
- @Input() class:string;
- @Input() count:number;
- @Input() showZone:boolean;
- @Input() minifyZone:boolean;
- constructor(private eventListenerService:EventListenerService) {}
+ @Input() type:ZoneInstanceType;
+ @Input() count:number;
+ @Input() visible:boolean;
+ @Input() minimized:boolean;
+ @Output() minimize: EventEmitter<any> = new EventEmitter<any>();
+ @Output() backgroundClick: EventEmitter<void> = new EventEmitter<void>();
+ private class:string;
+
+ constructor() {}
+
+ ngOnInit() {
+ this.class = ZoneInstanceType[this.type].toLowerCase();
+ }
private unminifyZone = () => {
- this.minifyZone = !this.minifyZone;
- this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_ZONE_SIZE_CHANGE);
+ this.minimize.emit();
+ }
+
+ private backgroundClicked = () => {
+ this.backgroundClick.emit();
}
}
\ No newline at end of file
diff --git a/catalog-ui/src/app/ng2/components/ui/canvas-zone/zone-instance/zone-instance.component.html b/catalog-ui/src/app/ng2/components/ui/canvas-zone/zone-instance/zone-instance.component.html
index d36b7ae..031b081 100644
--- a/catalog-ui/src/app/ng2/components/ui/canvas-zone/zone-instance/zone-instance.component.html
+++ b/catalog-ui/src/app/ng2/components/ui/canvas-zone/zone-instance/zone-instance.component.html
@@ -1,8 +1,10 @@
-<div class="zone-child mode-{{config.mode}}" [class.locked]="activeInstanceMode > MODE.HOVER"
- (mouseenter)="setMode(MODE.HOVER)" (mouseleave)="setMode(MODE.NONE)" (click)="setMode(MODE.SELECTED)">
- <div class="zone-child__handle" (click)="setMode(MODE.TAG, $event)">+</div>
- <div class="zone-child__body">
- <div class="zone-child__body-content">{{config.count || defaultIconText}}</div>
+<div tooltip="{{zoneInstance.instanceData.name}}" #currentComponent
+ class="zone-instance mode-{{zoneInstance.mode}}" [class.locked]="activeInstanceMode > MODE.HOVER" [class.hiding]="hidden"
+ (mouseenter)="setMode(MODE.HOVER)" (mouseleave)="setMode(MODE.NONE)" (click)="setMode(MODE.SELECTED, $event)">
+ <div *ngIf="zoneInstance.handle" class="target-handle {{zoneInstance.handle}}" (click)="tagHandleClicked($event)"></div>
+ <div *ngIf="!isViewOnly" class="zone-instance__handle" (click)="setMode(MODE.TAG, $event)">+</div>
+ <div class="zone-instance__body">
+ <div class="zone-instance__body-content">{{zoneInstance.assignments.length || defaultIconText}}</div>
</div>
- <div class="zone-child__name">{{config.name}}</div>
+ <div class="zone-instance__name">{{zoneInstance.instanceData.name}}</div>
</div>
\ No newline at end of file
diff --git a/catalog-ui/src/app/ng2/components/ui/canvas-zone/zone-instance/zone-instance.component.less b/catalog-ui/src/app/ng2/components/ui/canvas-zone/zone-instance/zone-instance.component.less
index a1d56df..b562c08 100644
--- a/catalog-ui/src/app/ng2/components/ui/canvas-zone/zone-instance/zone-instance.component.less
+++ b/catalog-ui/src/app/ng2/components/ui/canvas-zone/zone-instance/zone-instance.component.less
@@ -1,9 +1,12 @@
-.zone-child {
+@import '../../../../../../assets/styles/variables';
+
+.zone-instance {
position:relative;
width:76px;
margin:5px;
+ opacity:1;
- .zone-child__handle {
+ .zone-instance__handle {
display:none;
position:absolute;
right:4px;
@@ -11,33 +14,34 @@
width:22px;
height:22px;
cursor:pointer;
- border: solid white 1px;
+ border: solid @main_color_p 1px;
border-radius: 2px;
text-align: center;
font-weight:bold;
}
- .zone-child__body {
+ .zone-instance__body {
margin:0 auto;
width:43px;
height:43px;
display:flex;
padding:3px;
-
}
- .zone-child__body-content {
+ .zone-instance__body-content {
border-radius: 2px;
flex:1;
- color:white;
- font-size:18px;
+ color:@main_color_p;
+ font-size:16px;
text-align:center;
display:flex;
align-items: center;
justify-content: center;
+ box-shadow:none;
+ transition:box-shadow 5s;
}
- .zone-child__name {
+ .zone-instance__name {
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
@@ -45,66 +49,86 @@
}
/* Dynamic classes below */
+ .target-handle {
+ position:absolute;
+ width:18px;
+ height:18px;
+ display:block;
+ top: -4px;
+ right: 10px;
+ background-size: 100% 100%;
+ cursor: url("../../../../../../assets/styles/images/canvas-tagging-icons/policy_2.svg"), pointer;
+
+ &.tagged-policy {
+ background-image: url('../../../../../../assets/styles/images/canvas-tagging-icons/policy_added.svg');
+ }
+
+ &.tag-available {
+ background-image: url('../../../../../../assets/styles/images/canvas-tagging-icons/indication.svg');
+ }
+ }
+
+
&.mode-1, &.mode-2, &.mode-3 { //hover, selected, tag
- .zone-child__body {
+ .zone-instance__body {
border:solid 2px;
border-radius: 2px;
padding:2px;
cursor:pointer;
}
- .zone-child__handle{
+ }
+
+ &.mode-1, &.mode-2:hover{
+ .zone-instance__handle{
display:block;
- cursor:pointer;
}
}
&.locked {
- cursor: default;
+ cursor: inherit;
+ }
+
+ &.hiding {
+ opacity:0;
+ .zone-instance__body-content {
+ box-shadow: #CCC 0px 0px 15px;
+ }
}
- // &:not(.locked):hover .zone-child__handle{
- // display:block;
- // }
- .zone-child__body {
- cursor: default;
- }
- &.mode-3 .zone-child__handle {
+
+ &.mode-3 .zone-instance__handle {
width:24px;
height:24px;
right:3px;
top:9px;
display:block;
background-image: linear-gradient(-140deg, #009E98 0%, #97D648 100%);
- border: 2px solid #FFFFFF;
+ border: 2px solid @main_color_p;
border-radius: 2px;
box-shadow: inset 2px -2px 3px 0 #007A3E;
- cursor: pointer;
}
}
.sdc-canvas-zone.group-zone {
- .zone-child__handle {
- background-color:#009FDB;
+ .zone-instance__handle {
+ background-color:@main_color_a;
}
- .zone-child__body {
- border-color:#009FDB;
- }
- .zone-child__body-content {
- background: #009FDB;
+ .zone-instance__body {
+ border-color:@main_color_a;
+ .zone-instance__body-content {
+ background: @main_color_a;
+ }
}
}
.sdc-canvas-zone.policy-zone {
- .zone-child__handle {
- background-color:#0568AE;
+ .zone-instance__handle {
+ background-color:@main_color_r;
}
- .zone-child__body {
- border-color:#1287D9;
- .zone-child__body-content {
- background: #1287D9;
+ .zone-instance__body {
+ border-color:@main_color_r;
+ .zone-instance__body-content {
+ background: @main_color_r;
}
}
- .zone-child__body-content {
- background: #0568AE;
- }
}
\ No newline at end of file
diff --git a/catalog-ui/src/app/ng2/components/ui/canvas-zone/zone-instance/zone-instance.component.ts b/catalog-ui/src/app/ng2/components/ui/canvas-zone/zone-instance/zone-instance.component.ts
index 8057ae9..3c2dd45 100644
--- a/catalog-ui/src/app/ng2/components/ui/canvas-zone/zone-instance/zone-instance.component.ts
+++ b/catalog-ui/src/app/ng2/components/ui/canvas-zone/zone-instance/zone-instance.component.ts
@@ -1,5 +1,14 @@
-import { Component, Input, Output, EventEmitter, ViewEncapsulation } from '@angular/core';
-import { ZoneInstanceConfig, ZoneInstanceMode } from 'app/models/graph/zones/zone-child';
+import { Component, Input, Output, EventEmitter, ViewEncapsulation, OnInit, SimpleChange, ElementRef, ViewChild, SimpleChanges } from '@angular/core';
+import {
+ ZoneInstance, ZoneInstanceMode, ZoneInstanceType,
+ IZoneInstanceAssignment
+} from 'app/models/graph/zones/zone-instance';
+import { PoliciesService } from '../../../../services/policies.service';
+import { GroupsService } from '../../../../services/groups.service';
+import { IZoneService } from "../../../../../models/graph/zones/zone";
+import { EventListenerService } from 'app/services';
+import { GRAPH_EVENTS } from '../../../../../utils';
+import { Subject, Observable } from 'rxjs';
@Component({
selector: 'zone-instance',
@@ -7,22 +16,95 @@
styleUrls: ['./zone-instance.component.less'],
encapsulation: ViewEncapsulation.None
})
-export class ZoneInstanceComponent {
+export class ZoneInstanceComponent implements OnInit {
- @Input() config:ZoneInstanceConfig;
+ @Input() zoneInstance:ZoneInstance;
@Input() defaultIconText:string;
@Input() isActive:boolean;
+ @Input() isViewOnly:boolean;
@Input() activeInstanceMode: ZoneInstanceMode;
+ @Input() hidden:boolean;
+ @Input() forceSave:Subject<Function>;
@Output() modeChange: EventEmitter<any> = new EventEmitter<any>();
+ @Output() assignmentSaveStart: EventEmitter<void> = new EventEmitter<void>();
+ @Output() assignmentSaveComplete: EventEmitter<boolean> = new EventEmitter<boolean>();
+ @Output() tagHandleClick: EventEmitter<ZoneInstance> = new EventEmitter<ZoneInstance>();
+ @ViewChild('currentComponent') currentComponent: ElementRef;
private MODE = ZoneInstanceMode;
+ private zoneService:IZoneService;
- private setMode = (mode:ZoneInstanceMode, event?:any):void => {
- if(!this.isActive || this.isActive && mode == ZoneInstanceMode.TAG){ //when active, do not allow hover/select mode toggling
- this.modeChange.emit({newMode: mode, instance: this.config});
+ constructor(private policiesService:PoliciesService, private groupsService:GroupsService, private eventListenerService:EventListenerService){}
+
+ ngOnInit(){
+ if(this.zoneInstance.type == ZoneInstanceType.POLICY){
+ this.zoneService = this.policiesService;
+ } else {
+ this.zoneService = this.groupsService;
}
- if(event){
- event.stopPropagation();
+ this.forceSave.subscribe((afterSaveFunction:Function) => {
+ this.setMode(ZoneInstanceMode.TAG, null, afterSaveFunction);
+ })
+ }
+
+ ngOnChanges(changes:SimpleChanges) {
+ if(changes.hidden){
+ this.currentComponent.nativeElement.scrollIntoView({behavior: "smooth", block: "nearest", inline:"end"});
}
}
+ ngOnDestroy() {
+ this.forceSave.unsubscribe();
+ }
+
+ private setMode = (mode:ZoneInstanceMode, event?:any, afterSaveCallback?:Function):void => {
+
+ if(event){ //prevent event from handle and then repeat event from zone instance
+ event.stopPropagation();
+ }
+
+ if(!this.isActive && this.activeInstanceMode === ZoneInstanceMode.TAG) {
+ return; //someone else is tagging. No events allowed
+ }
+
+ if(this.isActive && this.zoneInstance.mode === ZoneInstanceMode.TAG){
+ if(mode !== ZoneInstanceMode.TAG) {
+ return; //ignore all other events. The only valid option is saving changes.
+ }
+
+ let oldAssignments:Array<IZoneInstanceAssignment> = this.zoneInstance.instanceData.getSavedAssignments();
+ if(this.zoneInstance.isZoneAssignmentChanged(oldAssignments, this.zoneInstance.assignments)) {
+
+ this.assignmentSaveStart.emit();
+
+ this.zoneService.updateZoneInstanceAssignments(this.zoneInstance.parentComponentType, this.zoneInstance.parentComponentID, this.zoneInstance.instanceData.uniqueId, this.zoneInstance.assignments).subscribe(
+ (success) => {
+ this.zoneInstance.instanceData.setSavedAssignments(this.zoneInstance.assignments);
+ if(this.zoneInstance.type === ZoneInstanceType.POLICY){
+ this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_POLICY_INSTANCE_UPDATE, this.zoneInstance.instanceData);
+ } else {
+ this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_GROUP_INSTANCE_UPDATE, this.zoneInstance.instanceData);
+ }
+ this.assignmentSaveComplete.emit(true);
+ if(afterSaveCallback) afterSaveCallback();
+ }, (error) => {
+ this.zoneInstance.assignments = oldAssignments;
+ this.assignmentSaveComplete.emit(false);
+ });
+ } else {
+ if(afterSaveCallback) afterSaveCallback();
+ }
+ this.modeChange.emit({newMode: ZoneInstanceMode.NONE, instance: this.zoneInstance});
+
+ } else {
+ this.modeChange.emit({newMode: mode, instance: this.zoneInstance});
+ }
+
+
+ }
+
+ private tagHandleClicked = (event:Event) => {
+ this.tagHandleClick.emit(this.zoneInstance);
+ event.stopPropagation();
+ };
+
}
\ No newline at end of file
diff --git a/catalog-ui/src/app/ng2/components/ui/dynamic-element/dynamic-element.component.ts b/catalog-ui/src/app/ng2/components/ui/dynamic-element/dynamic-element.component.ts
index d1e68f3..c15f92c 100644
--- a/catalog-ui/src/app/ng2/components/ui/dynamic-element/dynamic-element.component.ts
+++ b/catalog-ui/src/app/ng2/components/ui/dynamic-element/dynamic-element.component.ts
@@ -53,6 +53,7 @@
@ViewChild('target', { read: ViewContainerRef }) target: any;
@Input() type: any;
@Input() name: string;
+ @Input() testId: string;
@Input() readonly:boolean;
@Input() path:string;//optional param. used only for for subnetpoolid type
@@ -111,6 +112,7 @@
if (this.cmpRef) {
this.cmpRef.instance.name = this.name;
this.cmpRef.instance.type = this.type;
+ this.cmpRef.instance.testId = this.testId;
this.cmpRef.instance.value = this.value;
this.cmpRef.instance.readonly = this.readonly;
}
@@ -133,7 +135,7 @@
case DynamicElementComponentCreatorIdentifier.FLOAT:
this.createComponent(UiElementIntegerInputComponent);
- this.cmpRef.instance.pattern = /^[-+]?[0-9]+(\.[0-9]+)?([eE][-+]?[0-9]+)?$/;
+ this.cmpRef.instance.pattern = /^[-+]?[0-9]+(\.[0-9]+)?([eE][-+]?[0-9]+)?$/.source;
break;
case DynamicElementComponentCreatorIdentifier.STRING:
@@ -156,10 +158,10 @@
case DynamicElementComponentCreatorIdentifier.DEFAULT:
default:
this.createComponent(UiElementInputComponent);
- console.log("ERROR: No ui component to handle type: " + this.type);
+ console.log("ERROR: No ui-models component to handle type: " + this.type);
}
- // Subscribe to change event of of ui-element-basic and fire event to change the value
+ // Subscribe to change event of of ui-models-element-basic and fire event to change the value
this.cmpRef.instance.baseEmitter.subscribe((event) => { this.emitter.emit(event); });
this.cmpRef.instance.valueChange.subscribe((event) => { this.valueChange.emit(event); });
}
diff --git a/catalog-ui/src/app/ng2/components/ui/expand-collapse/expand-collapse.component.html b/catalog-ui/src/app/ng2/components/ui/expand-collapse/expand-collapse.component.html
new file mode 100644
index 0000000..83daca2
--- /dev/null
+++ b/catalog-ui/src/app/ng2/components/ui/expand-collapse/expand-collapse.component.html
@@ -0,0 +1,13 @@
+<h1 class="w-sdc-designer-sidebar-section-title"
+ tooltip="{{titleTooltip}}"
+ [ngClass]="{'expanded': state == 0, 'collapsed': state == 1}"
+ (click)="toggleState()">
+ {{caption}}<span class="w-sdc-designer-sidebar-section-title-icon"></span>
+ <ng-content select="header"></ng-content>
+ <span class="w-sdc-designer-sidebar-section-title-icon"></span>
+</h1>
+
+<div class="expand-collapse-content" [ngClass]="{'visible': state === 0, 'hidden': state === 1}">
+ <ng-content></ng-content>
+ <ng-content select="content"></ng-content>
+</div>
diff --git a/catalog-ui/src/app/ng2/components/ui/expand-collapse/expand-collapse.component.less b/catalog-ui/src/app/ng2/components/ui/expand-collapse/expand-collapse.component.less
new file mode 100644
index 0000000..e5dd252
--- /dev/null
+++ b/catalog-ui/src/app/ng2/components/ui/expand-collapse/expand-collapse.component.less
@@ -0,0 +1,7 @@
+.ellipsis-directive-more-less {
+ float: right;
+ margin-right: 10px;
+ line-height: 23px;
+ text-decoration: underline;
+ text-align: left;
+}
diff --git a/catalog-ui/src/app/ng2/components/ui/expand-collapse/expand-collapse.component.ts b/catalog-ui/src/app/ng2/components/ui/expand-collapse/expand-collapse.component.ts
new file mode 100644
index 0000000..0fa0d33
--- /dev/null
+++ b/catalog-ui/src/app/ng2/components/ui/expand-collapse/expand-collapse.component.ts
@@ -0,0 +1,56 @@
+/*-
+ * ============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, Output, ViewEncapsulation, AfterViewInit } from '@angular/core';
+
+export enum ExpandState {
+ EXPANDED,
+ COLLAPSED
+}
+
+@Component({
+ selector: 'ng2-expand-collapse',
+ templateUrl: './expand-collapse.component.html',
+ styleUrls: ['./expand-collapse.component.less'],
+ encapsulation: ViewEncapsulation.None
+})
+
+export class ExpandCollapseComponent implements AfterViewInit {
+ @Input() caption: String;
+ @Input() state: ExpandState;
+ @Input() titleTooltip: String;
+
+ constructor() {
+
+ }
+
+ toggleState():void {
+ if (this.state == ExpandState.EXPANDED) {
+ this.state = ExpandState.COLLAPSED;
+ } else {
+ this.state = ExpandState.EXPANDED;
+ }
+ }
+
+ ngAfterViewInit(): void {
+
+ }
+
+}
diff --git a/catalog-ui/src/app/ng2/components/ui/form-components/dropdown/ui-element-dropdown.component.html b/catalog-ui/src/app/ng2/components/ui/form-components/dropdown/ui-element-dropdown.component.html
index 805e5ac..c564abc 100644
--- a/catalog-ui/src/app/ng2/components/ui/form-components/dropdown/ui-element-dropdown.component.html
+++ b/catalog-ui/src/app/ng2/components/ui/form-components/dropdown/ui-element-dropdown.component.html
@@ -1,3 +1,3 @@
-<select name='{{name}}' [(ngModel)]="value" (change)="onChange()" [ngClass]="{'disabled':readonly}" data-tests-id="SelectType">
+<select name='{{name}}' [(ngModel)]="value" (change)="onChange()" [ngClass]="{'disabled':readonly}" [attr.data-tests-id]="'value-' + testId">
<option *ngFor="let ddvalue of values" [ngValue]="ddvalue.label != undefined ? ddvalue.value : ddvalue">{{ddvalue.label||ddvalue}}</option>
</select>
diff --git a/catalog-ui/src/app/ng2/components/ui/form-components/input/ui-element-input.component.html b/catalog-ui/src/app/ng2/components/ui/form-components/input/ui-element-input.component.html
index 057e731..fdba850 100644
--- a/catalog-ui/src/app/ng2/components/ui/form-components/input/ui-element-input.component.html
+++ b/catalog-ui/src/app/ng2/components/ui/form-components/input/ui-element-input.component.html
@@ -11,4 +11,5 @@
[formControl]="control"
tooltip="{{value}}"
[readonly]="readonly"
+ [attr.data-tests-id]="'value-' + testId"
/>
diff --git a/catalog-ui/src/app/ng2/components/ui/form-components/integer-input/ui-element-integer-input.component.html b/catalog-ui/src/app/ng2/components/ui/form-components/integer-input/ui-element-integer-input.component.html
index e1555e8..04307e4 100644
--- a/catalog-ui/src/app/ng2/components/ui/form-components/integer-input/ui-element-integer-input.component.html
+++ b/catalog-ui/src/app/ng2/components/ui/form-components/integer-input/ui-element-integer-input.component.html
@@ -11,4 +11,5 @@
[formControl]="control"
tooltip="{{value}}"
[readonly]="readonly"
+ [attr.data-tests-id]="'value-' + testId"
/>
diff --git a/catalog-ui/src/app/ng2/components/ui/form-components/popover-input/ui-element-popover-input.component.html b/catalog-ui/src/app/ng2/components/ui/form-components/popover-input/ui-element-popover-input.component.html
index 3bd51b4..3bc94de 100644
--- a/catalog-ui/src/app/ng2/components/ui/form-components/popover-input/ui-element-popover-input.component.html
+++ b/catalog-ui/src/app/ng2/components/ui/form-components/popover-input/ui-element-popover-input.component.html
@@ -7,7 +7,7 @@
[value]="value!=undefined?value:''"
disabled
/>
- <button [popover]="popoverForm" [ngClass]="{'disabled':readonly}">Edit</button>
+ <button [popover]="popoverForm" (onShown)="setEditValue()" [ngClass]="{'disabled':readonly}" [attr.data-tests-id] ="'edit-button-' + testId">Edit</button>
</div>
<popover-content #popoverForm [title]="name" [buttons]="buttonsArray" [placement]="'top'" [closeOnClickOutside]="true">
@@ -16,11 +16,12 @@
#textArea
class="subnet-value"
[ngClass]="{'error': control.invalid}"
- [(ngModel)]="value"
+ [(ngModel)]="editValue"
[attr.maxlength]="validation.propertyValue.max"
[attr.minlength]="validation.propertyValue.min"
[pattern]="pattern"
[formControl]="control"
+ [attr.data-tests-id]="'value-' + testId"
></textarea>
</div>
</popover-content>
diff --git a/catalog-ui/src/app/ng2/components/ui/form-components/popover-input/ui-element-popover-input.component.ts b/catalog-ui/src/app/ng2/components/ui/form-components/popover-input/ui-element-popover-input.component.ts
index 525cd17..f485d27 100644
--- a/catalog-ui/src/app/ng2/components/ui/form-components/popover-input/ui-element-popover-input.component.ts
+++ b/catalog-ui/src/app/ng2/components/ui/form-components/popover-input/ui-element-popover-input.component.ts
@@ -18,7 +18,7 @@
* ============LICENSE_END=========================================================
*/
-import {Component, ViewChild, ElementRef, Input} from '@angular/core';
+import {Component, ViewChild, ElementRef} from '@angular/core';
import {ButtonsModelMap, ButtonModel} from "app/models";
import {PopoverContentComponent} from "../../popover/popover-content.component";
import {UiElementBase, UiElementBaseInterface} from "../ui-element-base.component";
@@ -32,13 +32,14 @@
@ViewChild('textArea') textArea: ElementRef;
@ViewChild('popoverForm') popoverContentComponent: PopoverContentComponent;
+ editValue: any;
saveButton: ButtonModel;
buttonsArray: ButtonsModelMap;
constructor() {
super();
// Create Save button and insert to buttons map
- this.saveButton = new ButtonModel('save', 'blue', this.onChange);
+ this.saveButton = new ButtonModel('Set', 'blue', this.onChange.bind(this));
this.buttonsArray = { 'test': this.saveButton };
// Define the regex pattern for this controller
@@ -47,4 +48,15 @@
// Disable / Enable button according to validation
//this.control.valueChanges.subscribe(data => this.saveButton.disabled = this.control.invalid);
}
+
+ public setEditValue() {
+ // copy value to edit
+ this.editValue = angular.copy(this.value);
+ }
+
+ public onChange() {
+ this.popoverContentComponent.hide();
+ this.value = this.editValue;
+ super.onChange();
+ }
}
diff --git a/catalog-ui/src/app/ng2/components/ui/form-components/ui-element-base.component.ts b/catalog-ui/src/app/ng2/components/ui/form-components/ui-element-base.component.ts
index b4e9e7d..31fa7c3 100644
--- a/catalog-ui/src/app/ng2/components/ui/form-components/ui-element-base.component.ts
+++ b/catalog-ui/src/app/ng2/components/ui/form-components/ui-element-base.component.ts
@@ -46,9 +46,12 @@
@Input() name: string;
@Input() type: string;
+ @Input() path: string;
@Input() pattern: any;
@Input() readonly:boolean;
+ @Input() testId:string;
+
constructor() {
//this.control = new FormControl('', [Validators.required]);
this.control = new FormControl('', []);
diff --git a/catalog-ui/src/app/ng2/components/ui/forms/modal-forms.module.ts b/catalog-ui/src/app/ng2/components/ui/forms/modal-forms.module.ts
new file mode 100644
index 0000000..34404e5
--- /dev/null
+++ b/catalog-ui/src/app/ng2/components/ui/forms/modal-forms.module.ts
@@ -0,0 +1,27 @@
+import { NgModule } from "@angular/core";
+import { CommonModule } from '@angular/common';
+import { SdcUiComponentsModule } from "sdc-ui/lib/angular";
+import { ValueEditComponent } from './value-edit/value-edit.component';
+import { UnsavedChangesComponent } from "./unsaved-changes/unsaved-changes.component";
+import { UiElementsModule } from "../ui-elements.module";
+
+
+
+@NgModule({
+ declarations: [
+ ValueEditComponent,
+ UnsavedChangesComponent
+ ],
+ imports: [
+ CommonModule,
+ SdcUiComponentsModule,
+ UiElementsModule
+ ],
+ exports: [ValueEditComponent, UnsavedChangesComponent],
+ entryComponents: [ UnsavedChangesComponent
+ ],
+ providers: []
+})
+export class ModalFormsModule {
+
+}
\ No newline at end of file
diff --git a/catalog-ui/src/app/ng2/components/ui/forms/unsaved-changes/unsaved-changes.component.html b/catalog-ui/src/app/ng2/components/ui/forms/unsaved-changes/unsaved-changes.component.html
new file mode 100644
index 0000000..bdf21de
--- /dev/null
+++ b/catalog-ui/src/app/ng2/components/ui/forms/unsaved-changes/unsaved-changes.component.html
@@ -0,0 +1,6 @@
+<div class="unsaved-changes-modal">
+ <div class="message">
+ <p>Your changes {{isValidChangedData ? '' : '(invalid)'}} have not been saved.</p>
+ <p>Do you want to {{isValidChangedData ? 'save' : 'discard'}} them?</p>
+ </div>
+</div>
\ No newline at end of file
diff --git a/catalog-ui/src/app/ng2/components/ui/forms/unsaved-changes/unsaved-changes.component.ts b/catalog-ui/src/app/ng2/components/ui/forms/unsaved-changes/unsaved-changes.component.ts
new file mode 100644
index 0000000..b8fdeaf
--- /dev/null
+++ b/catalog-ui/src/app/ng2/components/ui/forms/unsaved-changes/unsaved-changes.component.ts
@@ -0,0 +1,17 @@
+import { Component, Input } from "@angular/core";
+
+@Component({
+ selector: 'unsaved-changes',
+ templateUrl: './unsaved-changes.component.html',
+ styleUrls: []
+})
+export class UnsavedChangesComponent {
+
+ @Input() isValidChangedData:boolean;
+
+ constructor(){
+ }
+
+
+
+}
\ No newline at end of file
diff --git a/catalog-ui/src/app/ng2/components/ui/forms/value-edit/value-edit.component.html b/catalog-ui/src/app/ng2/components/ui/forms/value-edit/value-edit.component.html
new file mode 100644
index 0000000..464b756
--- /dev/null
+++ b/catalog-ui/src/app/ng2/components/ui/forms/value-edit/value-edit.component.html
@@ -0,0 +1,12 @@
+<div class="name-update-container">
+ <sdc-input #updateNameInput
+ label="Instance Name"
+ required="true"
+ [maxLength]="50"
+ [(value)]="name"
+ testId="instanceName"></sdc-input>
+ <sdc-validation [validateElement]="updateNameInput" (validityChanged)="validityChanged($event)">
+ <sdc-required-validator message="Name is required."></sdc-required-validator>
+ <sdc-regex-validator message="Special characters not allowed." [pattern]="pattern"></sdc-regex-validator>
+ </sdc-validation>
+</div>
\ No newline at end of file
diff --git a/catalog-ui/src/app/ng2/components/ui/forms/value-edit/value-edit.component.less b/catalog-ui/src/app/ng2/components/ui/forms/value-edit/value-edit.component.less
new file mode 100644
index 0000000..b958ca1
--- /dev/null
+++ b/catalog-ui/src/app/ng2/components/ui/forms/value-edit/value-edit.component.less
@@ -0,0 +1,3 @@
+.name-update-container {
+ min-height: 90px;
+}
\ No newline at end of file
diff --git a/catalog-ui/src/app/ng2/components/ui/forms/value-edit/value-edit.component.ts b/catalog-ui/src/app/ng2/components/ui/forms/value-edit/value-edit.component.ts
new file mode 100644
index 0000000..08bc058
--- /dev/null
+++ b/catalog-ui/src/app/ng2/components/ui/forms/value-edit/value-edit.component.ts
@@ -0,0 +1,25 @@
+import { Component, Input } from "@angular/core";
+
+@Component({
+ selector: 'value-edit',
+ templateUrl: './value-edit.component.html',
+ styleUrls: ['./value-edit.component.less']
+})
+export class ValueEditComponent {
+
+ @Input() name:String;
+ @Input() validityChangedCallback: Function;
+
+ private pattern:string = "^[\\s\\w\&_.:-]{1,1024}$"
+ constructor(){
+ }
+
+ private validityChanged = (value):void => {
+ if(this.validityChangedCallback) {
+ this.validityChangedCallback(value);
+ }
+ }
+
+
+
+}
\ No newline at end of file
diff --git a/catalog-ui/src/app/ng2/components/ui/modal/add-elements/add-elements.component.html b/catalog-ui/src/app/ng2/components/ui/modal/add-elements/add-elements.component.html
new file mode 100644
index 0000000..ba89719
--- /dev/null
+++ b/catalog-ui/src/app/ng2/components/ui/modal/add-elements/add-elements.component.html
@@ -0,0 +1,30 @@
+<div class="component-add-element">
+ <div class="add-element-selection-container">
+ <sdc-dropdown class="add-element-selection" selectedOption="selectedElement" placeHolder="Please choose option"
+ (changed)="onElementSelected($event)" [options]="dropdownOptions"></sdc-dropdown>
+ <svg-icon-label class="add-element-button" [class.disabled]="!selectedElement"
+ name="plus-circle-o"
+ mode="primary"
+ size="medium"
+ label="ADD"
+ labelPlacement="right"
+ clickable="{{!!selectedElement}}"
+ (click)="addElement()">
+ </svg-icon-label>
+ </div>
+
+ <div class="elements-list">
+ <ul>
+ <li *ngFor="let element of existingElements" class="elements-list-item">
+ <span>{{element.name}}</span>
+ <svg-icon-label name="trash-o" clickable="true" size="small" class="elements-list-item-delete"
+ data-tests-id="delete_target" (click)="removeElement(element)"></svg-icon-label>
+ </li>
+ </ul>
+ <div *ngIf="existingElements.length===0" class="add-element-no-data">
+ <div class="add-element-no-data-title">No {{elementName}} have been added yet.</div>
+ <div class="add-element-no-data-content">Begin typing or select {{elementName}} above</div>
+ </div>
+ </div>
+
+</div>
\ No newline at end of file
diff --git a/catalog-ui/src/app/ng2/components/ui/modal/add-elements/add-elements.component.less b/catalog-ui/src/app/ng2/components/ui/modal/add-elements/add-elements.component.less
new file mode 100644
index 0000000..522483d
--- /dev/null
+++ b/catalog-ui/src/app/ng2/components/ui/modal/add-elements/add-elements.component.less
@@ -0,0 +1,61 @@
+@import "./../../../../../../assets/styles/variables-old";
+
+.component-add-element {
+
+ .add-element-selection-container {
+
+ display: flex;
+ flex-direction: row;
+ .add-element-selection {
+ flex: 2;
+ }
+
+ .add-element-button {
+ padding: 0px 0px 0px 15px;
+ &:not(.disabled) {
+ cursor:pointer;
+ }
+ }
+
+ }
+
+ .elements-list {
+ border: 1px solid #d2d2d2;
+ margin-top: 10px;
+ height: 300px;
+ overflow: auto;
+
+ .elements-list-item {
+ padding: 10px 20px 10px 20px;
+
+ &:first-child {
+ padding-top: 15px;
+ }
+
+ &:hover {
+ background-color: #f8f8f8;
+ .elements-list-item-delete {
+ visibility: visible;
+ }
+ }
+ }
+ }
+
+ .elements-list-item-delete {
+ float:right;
+ cursor: pointer;
+ visibility: hidden;
+ }
+
+
+ .add-element-no-data {
+ margin: 0 auto;
+ padding-top: 30px;
+ text-align: center;
+
+ .add-element-no-data-title {
+ font-family: @font-opensans-bold;
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/catalog-ui/src/app/ng2/components/ui/modal/add-elements/add-elements.component.ts b/catalog-ui/src/app/ng2/components/ui/modal/add-elements/add-elements.component.ts
new file mode 100644
index 0000000..1d05b27
--- /dev/null
+++ b/catalog-ui/src/app/ng2/components/ui/modal/add-elements/add-elements.component.ts
@@ -0,0 +1,65 @@
+/**
+ * Created by ob0695 on 11.04.2018.
+ */
+import {Component, Input} from "@angular/core";
+import {UiBaseObject} from "../../../../../models/ui-models/ui-base-object";
+import {IDropDownOption} from "sdc-ui/lib/angular/form-elements/dropdown/dropdown-models";
+
+@Component({
+ selector: 'add-elements',
+ templateUrl: './add-elements.component.html',
+ styleUrls: ['./add-elements.component.less']
+})
+
+export class AddElementsComponent {
+
+ @Input() elementsToAdd:Array<UiBaseObject>;
+ @Input() elementName: string;
+
+ private existingElements:Array<UiBaseObject>;
+ private dropdownOptions:Array<IDropDownOption>;
+ private selectedElement:IDropDownOption;
+
+ ngOnInit() {
+ this.existingElements = [];
+ this.convertElementToDropdownDisplay();
+
+ }
+
+ private convertElementToDropdownDisplay = () => {
+ this.dropdownOptions = [];
+ _.forEach(this.elementsToAdd, (elementToAdd:UiBaseObject) =>{
+ this.dropdownOptions.push({label:elementToAdd.name, value: elementToAdd.uniqueId })
+ });
+ }
+
+ onElementSelected(selectedElement:IDropDownOption):void {
+ this.selectedElement = selectedElement
+ }
+
+ addElement():void {
+
+ if(this.selectedElement){
+ this.dropdownOptions = _.reject(this.dropdownOptions, (option: IDropDownOption) => { // remove from dropDown
+ return option.value === this.selectedElement.value;
+ });
+
+ let selected = _.find(this.elementsToAdd, (element:UiBaseObject) => {
+ return this.selectedElement.value === element.uniqueId;
+ });
+
+ this.elementsToAdd =_.without(this.elementsToAdd, selected); // remove from optional elements to add
+ this.existingElements.push(selected); // add to existing element list
+ this.selectedElement = undefined;
+ } else {
+ console.log("no element selected"); //TODO:show error?
+ }
+ }
+
+ removeElement(element:UiBaseObject):void {
+
+ this.existingElements =_.without(this.existingElements, element); // remove from optional elements to add
+ this.dropdownOptions.push({label:element.name, value: element.uniqueId });
+ this.elementsToAdd.push(element);
+ }
+}
diff --git a/catalog-ui/src/app/ng2/components/ui/modal/add-elements/add-elements.module.ts b/catalog-ui/src/app/ng2/components/ui/modal/add-elements/add-elements.module.ts
new file mode 100644
index 0000000..a1c34f5
--- /dev/null
+++ b/catalog-ui/src/app/ng2/components/ui/modal/add-elements/add-elements.module.ts
@@ -0,0 +1,30 @@
+/**
+ * Created by ob0695 on 11.04.2018.
+ */
+import {NgModule} from "@angular/core";
+import {SdcUiComponentsModule} from "sdc-ui/lib/angular/index";
+import {AddElementsComponent} from "./add-elements.component";
+import {CommonModule} from "@angular/common";
+
+/**
+ * Created by ob0695 on 9.04.2018.
+ */
+@NgModule({
+ declarations: [
+ AddElementsComponent
+ ],
+
+ imports: [
+ CommonModule,
+ SdcUiComponentsModule
+ ],
+
+ entryComponents: [
+ AddElementsComponent
+ ],
+ exports: [],
+ providers: []
+})
+export class AddElementsModule {
+
+}
diff --git a/catalog-ui/src/app/ng2/components/ui/modal/modal.component.html b/catalog-ui/src/app/ng2/components/ui/modal/modal.component.html
index 6fc55d1..1708fc4 100644
--- a/catalog-ui/src/app/ng2/components/ui/modal/modal.component.html
+++ b/catalog-ui/src/app/ng2/components/ui/modal/modal.component.html
@@ -1,6 +1,5 @@
<div class="custom-modal {{input.size}}">
<div class="ng2-modal-content"
- ngDraggable
[ngDraggable]="input.isMovable"
[handle]="ModalHandle"
[bounds]="ModalBounds"
diff --git a/catalog-ui/src/app/ng2/components/ui/palette-animation/palette-animation.component.ts b/catalog-ui/src/app/ng2/components/ui/palette-animation/palette-animation.component.ts
index 609a1fc..7e45b9e 100644
--- a/catalog-ui/src/app/ng2/components/ui/palette-animation/palette-animation.component.ts
+++ b/catalog-ui/src/app/ng2/components/ui/palette-animation/palette-animation.component.ts
@@ -24,6 +24,7 @@
import { EventListenerService } from 'app/services';
import { GRAPH_EVENTS } from 'app/utils';
import { Point } from 'app/models';
+import { ZoneInstanceType, ZoneInstance } from '../../../../models/graph/zones/zone-instance';
@@ -37,8 +38,9 @@
@Input() from : Point;
@Input() to : Point;
+ @Input() type: ZoneInstanceType;
@Input() iconName : string;
- @Input() data : any;
+ @Input() zoneInstance : ZoneInstance;
public animation;
private visible:boolean = false;
@@ -47,6 +49,11 @@
constructor(private eventListenerService:EventListenerService) {}
+
+ ngOnDestroy(){
+ this.zoneInstance.hidden = false; //if animation component is destroyed before animation is complete
+ }
+
public runAnimation() {
this.visible = true;
let positionDiff:Point = new Point(this.to.x - this.from.x, this.to.y - this.from.y);
@@ -57,7 +64,7 @@
public animationComplete = (e) => {
this.visible = false;
- this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_FINISH_ANIMATION_ZONE);
+ this.zoneInstance.hidden = false;
};
diff --git a/catalog-ui/src/app/ng2/components/ui/palette-popup-panel/palette-popup-panel.component.ts b/catalog-ui/src/app/ng2/components/ui/palette-popup-panel/palette-popup-panel.component.ts
index d30d5f6..a10ca7d 100644
--- a/catalog-ui/src/app/ng2/components/ui/palette-popup-panel/palette-popup-panel.component.ts
+++ b/catalog-ui/src/app/ng2/components/ui/palette-popup-panel/palette-popup-panel.component.ts
@@ -35,7 +35,8 @@
public addZoneInstance(): void {
if(this.displayComponent) {
- this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_ADD_COMPONENT_INSTANCE_ZONE_START, this.component, this.displayComponent, this.popupPanelPosition);
+ this.eventListenerService.notifyObservers(GRAPH_EVENTS.ON_ADD_ZONE_INSTANCE_FROM_PALETTE, this.component, this.displayComponent, this.popupPanelPosition);
+ this.hidePopupPanel();
}
}
diff --git a/catalog-ui/src/app/ng2/components/ui/tile/tile.component.html b/catalog-ui/src/app/ng2/components/ui/tile/tile.component.html
new file mode 100644
index 0000000..a7a7b2c
--- /dev/null
+++ b/catalog-ui/src/app/ng2/components/ui/tile/tile.component.html
@@ -0,0 +1,28 @@
+<div class="sdc-tile sdc-tile-fix-width">
+
+ <div class='sdc-tile-header' [ngClass]="{'purple': component.isResource(), 'blue': !component.isResource()}">
+ <div *ngIf="component.isResource()" data-tests-id="asset-type">{{component.getComponentSubType()}}</div>
+ <div *ngIf="component.isService()">S</div>
+ </div>
+
+ <div class='sdc-tile-content' data-tests-id="dashboard-Elements" (click)="tileClicked()">
+ <div class='sdc-tile-content-icon'>
+ <div [ngClass]="[component.iconSprite, component.icon]" [ngClass]="{'sprite-resource-icons': component.isResource(), 'sprite-services-icons': component.isService()}"
+ [attr.data-tests-id]="component.name"></div>
+ </div>
+
+ <div class='sdc-tile-content-info'>
+ <div class="sdc-tile-info-line title" [attr.data-tests-id]="component.name | resourceName" [tooltip]="component.name | resourceName" [tooltipDisabled]="!hasEllipsis">
+ <multiline-ellipsis className="w-sdc-tile-multiline-ellipsis" [lines]="3" (hasEllipsisChanged)="hasEllipsis = $event">{{component.name | resourceName}}</multiline-ellipsis>
+ </div>
+ <div class="sdc-tile-info-line subtitle" [attr.data-tests-id]="component.name+'Version'">V {{component.version}}</div>
+ </div>
+ </div>
+
+ <div class='sdc-tile-footer'>
+ <div class="sdc-tile-footer-content">
+ <div class='sdc-tile-footer-text'>{{component.getStatus(sdcMenu)}}</div>
+ </div>
+ </div>
+
+</div>
diff --git a/catalog-ui/src/app/ng2/components/ui/tile/tile.component.less b/catalog-ui/src/app/ng2/components/ui/tile/tile.component.less
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/catalog-ui/src/app/ng2/components/ui/tile/tile.component.less
diff --git a/catalog-ui/src/app/ng2/components/ui/tile/tile.component.ts b/catalog-ui/src/app/ng2/components/ui/tile/tile.component.ts
new file mode 100644
index 0000000..b6f6358
--- /dev/null
+++ b/catalog-ui/src/app/ng2/components/ui/tile/tile.component.ts
@@ -0,0 +1,24 @@
+import {Component, Input, Output, Inject, EventEmitter} from '@angular/core';
+import {Component as ComponentModel} from 'app/models';
+import {SdcMenuToken, IAppMenu} from "../../../config/sdc-menu.config";
+
+@Component({
+ selector: 'ui-tile',
+ templateUrl: './tile.component.html',
+ styleUrls: ['./tile.component.less']
+})
+export class TileComponent {
+ @Input() public component: ComponentModel;
+ @Output() public onTileClick: EventEmitter<ComponentModel>;
+
+ public hasEllipsis: boolean;
+
+ constructor(@Inject(SdcMenuToken) public sdcMenu:IAppMenu) {
+ this.onTileClick = new EventEmitter<ComponentModel>();
+ this.hasEllipsis = false;
+ }
+
+ public tileClicked() {
+ this.onTileClick.emit(this.component);
+ }
+}
diff --git a/catalog-ui/src/app/ng2/components/ui/tile/tile.module.ts b/catalog-ui/src/app/ng2/components/ui/tile/tile.module.ts
new file mode 100644
index 0000000..55b3440
--- /dev/null
+++ b/catalog-ui/src/app/ng2/components/ui/tile/tile.module.ts
@@ -0,0 +1,15 @@
+import { NgModule } from '@angular/core';
+import { BrowserModule } from '@angular/platform-browser';
+import { TileComponent } from './tile.component';
+import { GlobalPipesModule } from "../../../pipes/global-pipes.module";
+import { TooltipModule } from "../tooltip/tooltip.module";
+import {MultilineEllipsisModule} from "../../../shared/multiline-ellipsis/multiline-ellipsis.module";
+
+
+@NgModule({
+ imports: [BrowserModule, GlobalPipesModule, TooltipModule, MultilineEllipsisModule],
+ declarations: [TileComponent],
+ exports: [TileComponent],
+ entryComponents: [TileComponent]
+})
+export class TileModule { }
diff --git a/catalog-ui/src/app/ng2/components/ui/ui-elements.module.ts b/catalog-ui/src/app/ng2/components/ui/ui-elements.module.ts
index 4431473..e905db7 100644
--- a/catalog-ui/src/app/ng2/components/ui/ui-elements.module.ts
+++ b/catalog-ui/src/app/ng2/components/ui/ui-elements.module.ts
@@ -20,26 +20,28 @@
import { NgModule } from '@angular/core';
import { NavbarModule } from "./navbar/navbar.module";
-import {DynamicElementModule} from "./dynamic-element/dynamic-element.module";
-import {FormElementsModule} from "./form-components/form-elements.module";
-import {LoaderComponent} from "./loader/loader.component";
-import {ModalModule} from "./modal/modal.module";
-import {PopoverModule} from "./popover/popover.module";
-import {SearchBarComponent} from "./search-bar/search-bar.component";
-import {SearchWithAutoCompleteComponent} from "./search-with-autocomplete/search-with-autocomplete.component";
-import {PalettePopupPanelComponent} from "./palette-popup-panel/palette-popup-panel.component";
-import {ZoneContainerComponent} from "./canvas-zone/zone-container.component";
-import {ZoneInstanceComponent } from "./canvas-zone/zone-instance/zone-instance.component";
-import {PaletteAnimationComponent} from "./palette-animation/palette-animation.component"
-import {TabModule} from "./tabs/tabs.module";
-import {TooltipModule} from "./tooltip/tooltip.module";
-import {CommonModule} from "@angular/common";
-import {FormsModule} from "@angular/forms";
-import {BrowserModule} from "@angular/platform-browser";
-import {MultiStepsWizardModule} from "./multi-steps-wizard/multi-steps-wizard.module";
-import {MenuListModule} from "./menu/menu-list.module";
-import {MenuListNg2Module} from "../downgrade-wrappers/menu-list-ng2/menu-list-ng2.module";
-//import {SdcUiComponentsModule} from "sdc-ui/lib/angular";
+import { DynamicElementModule } from "./dynamic-element/dynamic-element.module";
+import { FormElementsModule } from "./form-components/form-elements.module";
+import { LoaderComponent } from "./loader/loader.component";
+import { ModalModule } from "./modal/modal.module";
+import { PopoverModule } from "./popover/popover.module";
+import { SearchBarComponent } from "./search-bar/search-bar.component";
+import { SearchWithAutoCompleteComponent } from "./search-with-autocomplete/search-with-autocomplete.component";
+import { PalettePopupPanelComponent } from "./palette-popup-panel/palette-popup-panel.component";
+import { ZoneContainerComponent } from "./canvas-zone/zone-container.component";
+import { ZoneInstanceComponent } from "./canvas-zone/zone-instance/zone-instance.component";
+import { PaletteAnimationComponent } from "./palette-animation/palette-animation.component"
+import { TabModule } from "./tabs/tabs.module";
+import { TooltipModule } from "./tooltip/tooltip.module";
+import { CommonModule } from "@angular/common";
+import { FormsModule } from "@angular/forms";
+import { BrowserModule } from "@angular/platform-browser";
+import { MultiStepsWizardModule } from "./multi-steps-wizard/multi-steps-wizard.module";
+import { MenuListModule } from "./menu/menu-list.module";
+import { MenuListNg2Module } from "../downgrade-wrappers/menu-list-ng2/menu-list-ng2.module";
+import { ExpandCollapseComponent } from './expand-collapse/expand-collapse.component';
+import { SdcUiComponentsModule } from "sdc-ui/lib/angular";
+import { TileModule } from "./tile/tile.module";
@NgModule({
declarations: [
@@ -49,11 +51,12 @@
PalettePopupPanelComponent,
ZoneContainerComponent,
ZoneInstanceComponent,
- PaletteAnimationComponent
+ PaletteAnimationComponent,
+ ExpandCollapseComponent
],
-
+
imports: [
- //SdcUiComponentsModule,
+ SdcUiComponentsModule,
BrowserModule,
FormsModule,
CommonModule,
@@ -66,7 +69,8 @@
TooltipModule,
MultiStepsWizardModule,
MenuListModule,
- MenuListNg2Module
+ MenuListNg2Module,
+ TileModule
],
exports: [
LoaderComponent,
@@ -85,7 +89,9 @@
TooltipModule,
MenuListModule,
MenuListNg2Module,
- PaletteAnimationComponent
+ PaletteAnimationComponent,
+ ExpandCollapseComponent,
+ TileModule
],
entryComponents: [SearchWithAutoCompleteComponent, PalettePopupPanelComponent, ZoneContainerComponent, ZoneInstanceComponent, PaletteAnimationComponent]
})
diff --git a/catalog-ui/src/app/ng2/config/sdc-menu.config.factory.ts b/catalog-ui/src/app/ng2/config/sdc-menu.config.factory.ts
new file mode 100644
index 0000000..4417c32
--- /dev/null
+++ b/catalog-ui/src/app/ng2/config/sdc-menu.config.factory.ts
@@ -0,0 +1,6 @@
+import {IAppMenu} from "app/models";
+
+export function getSdcMenu() : IAppMenu{
+ const sdcMenu:IAppMenu = require('./../../../../configurations/menu.js');
+ return sdcMenu;
+}
diff --git a/catalog-ui/src/app/ng2/config/sdc-menu.config.ts b/catalog-ui/src/app/ng2/config/sdc-menu.config.ts
new file mode 100644
index 0000000..07680b5
--- /dev/null
+++ b/catalog-ui/src/app/ng2/config/sdc-menu.config.ts
@@ -0,0 +1,12 @@
+import {Provider, OpaqueToken} from "@angular/core";
+import {getSdcMenu} from "./sdc-menu.config.factory";
+import {IAppMenu} from "app/models";
+
+export { IAppMenu };
+
+export const SdcMenuToken = new OpaqueToken('SdcMenuToken');
+
+export const SdcMenu:Provider = {
+ provide: SdcMenuToken,
+ useFactory: getSdcMenu
+};
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 0000000..97fb71e
--- /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 0000000..12a3b72
--- /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 0000000..0bc342c
--- /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 0000000..2a03d94
--- /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 0000000..24f8107
--- /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 0000000..0fa467c
--- /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 0000000..abebe0b
--- /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 0000000..e848283
--- /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 0000000..d558e88
--- /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 0000000..b256d7e
--- /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 0000000..c6d3add
--- /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 0000000..726bc67
--- /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 0000000..4507929
--- /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 0000000..6e6af0c
--- /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 0000000..806b831
--- /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 0000000..67e7f08
--- /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 0000000..2ab2130
--- /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 0000000..9ae7349
--- /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 0000000..19f6412
--- /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 0000000..0acfece
--- /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 0000000..731d6a3
--- /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="​{{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 0000000..9bbc765
--- /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 0000000..ab659a3
--- /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 0000000..bde0a14
--- /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 0000000..aa8e751
--- /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 0000000..3c875fd
--- /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/services/responses/properties.response.ts b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-information-tab.component.ts
similarity index 65%
copy from catalog-ui/src/app/ng2/services/responses/properties.response.ts
copy to catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-information-tab.component.ts
index a1c0660..2660222 100644
--- a/catalog-ui/src/app/ng2/services/responses/properties.response.ts
+++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/groups/group-information-tab.component.ts
@@ -7,9 +7,9 @@
* 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.
@@ -18,10 +18,22 @@
* ============LICENSE_END=========================================================
*/
-export class PropertiesResponse {
- properties: Array<Property>;
-}
+import * as _ from "lodash";
+import { Component, Inject, Input, Output, EventEmitter } from "@angular/core";
+import { GroupInstance } from 'app/models/graph/zones/group-instance';
-class Property {
- name: string
+@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 0000000..f298a39
--- /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 0000000..1006e86
--- /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 0000000..148f213
--- /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 0000000..9de489e
--- /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 0000000..e69de29
--- /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 0000000..6907934
--- /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 0000000..94b6619
--- /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 0000000..975d5c6
--- /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 0000000..50797f8
--- /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 0000000..a1b942d
--- /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/services/responses/properties.response.ts b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-information-tab.component.ts
similarity index 60%
copy from catalog-ui/src/app/ng2/services/responses/properties.response.ts
copy to catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-information-tab.component.ts
index a1c0660..3639639 100644
--- a/catalog-ui/src/app/ng2/services/responses/properties.response.ts
+++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/policies/policy-information-tab.component.ts
@@ -7,9 +7,9 @@
* 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.
@@ -18,10 +18,22 @@
* ============LICENSE_END=========================================================
*/
-export class PropertiesResponse {
- properties: Array<Property>;
-}
+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';
-class Property {
- name: string
+@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 0000000..9de489e
--- /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 0000000..e69de29
--- /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 0000000..5862135
--- /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 0000000..b11ad7e
--- /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 0000000..1e27399
--- /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 0000000..38dc19e
--- /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 0000000..097b3a4
--- /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 0000000..cd7ace2
--- /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 0000000..b79f4d9
--- /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 0000000..430b272
--- /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 0000000..1777d54
--- /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 0000000..53599d6
--- /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 0000000..57f6be8
--- /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 bf5ec4c..af8dcb4 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 @@
// 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 03e9f1f..5142bba 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 40818bc..5a21e86 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 { 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 {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 @@
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 @@
@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 @@
@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 @@
}, 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 @@
// 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 @@
}
- 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)) {
- this.componentInstanceServiceNg2
- .getComponentInstanceInputs(this.component, resourceInstance)
- .subscribe(response => {
- instanceBePropertiesMap[resourceInstance.uniqueId] = response;
- this.processInstancePropertiesResponse(instanceBePropertiesMap, true);
- this.loadingProperties = false;
+ 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
+ }
- }, error => {
- }); //ignore error
- } else {
+ this.resourceIsReadonly = (instance.componentName === "vnfConfiguration");
+ } else if (instance instanceof GroupInstance) {
+ let instanceBePropertiesMap: InstanceBePropertiesMap = new InstanceBePropertiesMap();
this.componentInstanceServiceNg2
- .getComponentInstanceProperties(this.component, resourceInstance.uniqueId)
- .subscribe(response => {
- instanceBePropertiesMap[resourceInstance.uniqueId] = response;
+ .getComponentGroupInstanceProperties(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 if (instance instanceof PolicyInstance) {
+ let instanceBePropertiesMap: InstanceBePropertiesMap = new InstanceBePropertiesMap();
+ this.componentInstanceServiceNg2
+ .getComponentPolicyInstanceProperties(this.component, this.selectedInstanceData.uniqueId)
+ .subscribe((response) => {
+ instanceBePropertiesMap[instance.uniqueId] = response;
+ this.processInstancePropertiesResponse(instanceBePropertiesMap, false);
+ this.loadingProperties = false;
+ });
+ } else {
+ this.loadingProperties = false;
}
if (this.searchPropertyName) {
@@ -289,7 +312,7 @@
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 @@
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 @@
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,34 @@
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);
- 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)
+ .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((resProp) => {
@@ -420,7 +461,19 @@
this.propertiesUtils.resetPropertyValue(changedProp, resProp.value);
});
resolve(response);
- console.log("updated instance properties: ", response);
+ console.log("updated group instance properties: ", response);
+ };
+ } else if (this.selectedInstanceData instanceof PolicyInstance) {
+ request = this.componentInstanceServiceNg2
+ .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) => {
+ const changedProp = <PropertyFEModel>this.changedData.shift();
+ this.propertiesUtils.resetPropertyValue(changedProp, resProp.value);
+ });
+ resolve(response);
+ console.log("updated policy instance properties: ", response);
};
}
} else if (this.isInputsTabSelected) {
@@ -484,66 +537,59 @@
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 @@
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 @@
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 bbbf6ae..e029b7f 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 1643324..e4fc1d4 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 @@
@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 @@
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 @@
}
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 @@
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 @@
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 @@
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 @@
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 96cd83ee..76c5c53 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 dac41a3..bffb1c5 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 @@
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 @@
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 8a31c76..39c4191 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 aff597f..291119f 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 04083e8..1625ab4 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 @@
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 @@
});
this.onAddServicePath = this.input.onCreateServicePath;
this.onEditServicePath = this.input.onEditServicePath;
+ this.isViewOnly = this.input.isViewOnly;
}
deletePath = (id:string):void => {
diff --git a/catalog-ui/src/app/ng2/pipes/global-pipes.module.ts b/catalog-ui/src/app/ng2/pipes/global-pipes.module.ts
index 3761aa8..758a7e8 100644
--- a/catalog-ui/src/app/ng2/pipes/global-pipes.module.ts
+++ b/catalog-ui/src/app/ng2/pipes/global-pipes.module.ts
@@ -2,6 +2,7 @@
import {SearchFilterPipe} from "./searchFilter.pipe";
import {KeysPipe} from "./keys.pipe";
import {GroupByPipe} from "./groupBy.pipe";
+import {ResourceNamePipe} from "./resource-name.pipe";
import {NgModule} from "@angular/core";
import {SafeUrlSanitizerPipe} from "./safeUrlSanitizer.pipe";
@@ -10,15 +11,17 @@
ContentAfterLastDotPipe,
GroupByPipe,
KeysPipe,
+ SafeUrlSanitizerPipe,
SearchFilterPipe,
- SafeUrlSanitizerPipe
+ ResourceNamePipe
],
exports: [
ContentAfterLastDotPipe,
GroupByPipe,
KeysPipe,
+ SafeUrlSanitizerPipe,
SearchFilterPipe,
- SafeUrlSanitizerPipe
+ ResourceNamePipe
]
})
diff --git a/catalog-ui/src/app/ng2/services/responses/properties.response.ts b/catalog-ui/src/app/ng2/pipes/resource-name.pipe.ts
similarity index 65%
rename from catalog-ui/src/app/ng2/services/responses/properties.response.ts
rename to catalog-ui/src/app/ng2/pipes/resource-name.pipe.ts
index a1c0660..fdf9526 100644
--- a/catalog-ui/src/app/ng2/services/responses/properties.response.ts
+++ b/catalog-ui/src/app/ng2/pipes/resource-name.pipe.ts
@@ -7,9 +7,9 @@
* 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.
@@ -18,10 +18,17 @@
* ============LICENSE_END=========================================================
*/
-export class PropertiesResponse {
- properties: Array<Property>;
-}
-class Property {
- name: string
+import { Pipe, PipeTransform } from '@angular/core';
+
+@Pipe({name: 'resourceName'})
+export class ResourceNamePipe implements PipeTransform {
+ transform(value) : any {
+ if (value) {
+ //newName = _.last(newName.split('.'));
+ const newName:string =
+ _.last(value.split(/tosca\.nodes\..*network\..*relationships\..*org\.openecomp\..*resource\.nfv\..*nodes\.module\..*cp\..*vl\./));
+ return (newName) ? newName : value;
+ }
+ }
}
diff --git a/catalog-ui/src/app/ng2/services/archive.service.ts b/catalog-ui/src/app/ng2/services/archive.service.ts
new file mode 100644
index 0000000..83f1c50
--- /dev/null
+++ b/catalog-ui/src/app/ng2/services/archive.service.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 { Injectable, Inject } from "@angular/core";
+import { Observable } from "rxjs/Observable";
+import { HttpService } from "./http.service";
+import { SdcConfigToken, ISdcConfig } from "../config/sdc-config.config";
+import { Component } from "../../models";
+import { ComponentFactory } from 'app/utils/component-factory';
+
+
+@Injectable()
+export class ArchiveService {
+ protected baseUrl;
+
+ constructor(private http: HttpService, @Inject(SdcConfigToken) sdcConfig:ISdcConfig, private componentFactory:ComponentFactory/*, @Inject(ComponentFactory) componentFactory */) {
+ this.baseUrl = sdcConfig.api.root ;
+ }
+
+ public getArchiveCatalog() {
+ let archiveCatalogItems:Component[] = [];
+ let archiveCatalogResourceItems:Component[] = [];
+ let archiveCatalogServiceItems:Component[] = [];
+
+ return this.http.get(this.baseUrl + '/v1/catalog/archive/', {}).map(res => {
+ let archiveCatalogObject = res.json();
+ if (archiveCatalogObject.resources) archiveCatalogResourceItems = this.getResourceItems(archiveCatalogObject.resources);
+ if (archiveCatalogObject.services) archiveCatalogServiceItems = this.getServiceItems(archiveCatalogObject.services);
+ archiveCatalogItems = [].concat(archiveCatalogResourceItems, archiveCatalogServiceItems);
+
+ return archiveCatalogItems;
+ });
+ }
+
+
+ private getResourceItems(resources){
+ let resourceItems = resources.map((resource)=>{
+ return this.componentFactory.createResource(resource)
+ })
+ return resourceItems;
+ }
+
+ private getServiceItems(services){
+ let serviceItems = services.map((service)=>{
+ return this.componentFactory.createService(service)
+ })
+ return serviceItems;
+ }
+
+}
\ No newline at end of file
diff --git a/catalog-ui/src/app/ng2/services/component-instance-services/component-instance.service.ts b/catalog-ui/src/app/ng2/services/component-instance-services/component-instance.service.ts
index 0947b2a..1575002 100644
--- a/catalog-ui/src/app/ng2/services/component-instance-services/component-instance.service.ts
+++ b/catalog-ui/src/app/ng2/services/component-instance-services/component-instance.service.ts
@@ -92,4 +92,32 @@
return res.json().map((resInput) => new PropertyBEModel(resInput));
});
}
+
+ getComponentGroupInstanceProperties(component: Component, groupInstanceId: string): Observable<Array<PropertyBEModel>> {
+ return this.http.get(this.baseUrl + component.getTypeUrl() + component.uniqueId + '/groups/' + groupInstanceId + '/properties')
+ .map((res: Response) => {
+ return CommonUtils.initBeProperties(res.json());
+ });
+ }
+
+ updateComponentGroupInstanceProperties(component: Component, groupInstanceId: string, properties: PropertyBEModel[]): Observable<Array<PropertyBEModel>> {
+ return this.http.put(this.baseUrl + component.getTypeUrl() + component.uniqueId + '/groups/' + groupInstanceId + '/properties', properties)
+ .map((res: Response) => {
+ return res.json().map((resProperty) => new PropertyBEModel(resProperty));
+ });
+ }
+
+ getComponentPolicyInstanceProperties(component: Component, policyInstanceId: string): Observable<Array<PropertyBEModel>> {
+ return this.http.get(this.baseUrl + component.getTypeUrl() + component.uniqueId + '/policies/' + policyInstanceId + '/properties')
+ .map((res: Response) => {
+ return CommonUtils.initBeProperties(res.json());
+ });
+ }
+
+ updateComponentPolicyInstanceProperties(component: Component, policyInstanceId: string, properties: PropertyBEModel[]): Observable<Array<PropertyBEModel>> {
+ return this.http.put(this.baseUrl + component.getTypeUrl() + component.uniqueId + '/policies/' + policyInstanceId + '/properties', properties)
+ .map((res: Response) => {
+ return res.json().map((resProperty) => new PropertyBEModel(resProperty));
+ });
+ }
}
diff --git a/catalog-ui/src/app/ng2/services/component-services/component.service.ts b/catalog-ui/src/app/ng2/services/component-services/component.service.ts
index 381995d..3546ebd 100644
--- a/catalog-ui/src/app/ng2/services/component-services/component.service.ts
+++ b/catalog-ui/src/app/ng2/services/component-services/component.service.ts
@@ -25,6 +25,7 @@
import 'rxjs/add/operator/toPromise';
import {Response, URLSearchParams} from '@angular/http';
import { Component, InputBEModel, InstancePropertiesAPIMap, FilterPropertiesAssignmentData, OperationModel, CreateOperationResponse} from "app/models";
+import {downgradeInjectable} from '@angular/upgrade/static';
import {COMPONENT_FIELDS} from "app/utils";
import {ComponentGenericResponse} from "../responses/component-generic-response";
import {InstanceBePropertiesMap} from "../../../models/properties-inputs/property-fe-map";
@@ -32,6 +33,9 @@
import { ComponentType, ServerTypeUrl } from "../../../utils/constants";
import { HttpService } from '../http.service';
import {SdcConfigToken, ISdcConfig} from "../../config/sdc-config.config";
+import {IDependenciesServerResponse} from "../responses/dependencies-server-response";
+import {AutomatedUpgradeGenericResponse} from "../responses/automated-upgrade-response";
+import {IAutomatedUpgradeRequestObj} from "../../pages/automated-upgrade/automated-upgrade.service";
declare var angular:angular.IAngularStatic;
@@ -83,7 +87,11 @@
}
getComponentCompositionData(component:Component):Observable<ComponentGenericResponse> {
- return this.getComponentDataByFieldsName(component.componentType, component.uniqueId, [COMPONENT_FIELDS.COMPONENT_INSTANCES_RELATION, COMPONENT_FIELDS.COMPONENT_INSTANCES, COMPONENT_FIELDS.COMPONENT_POLICIES, COMPONENT_FIELDS.COMPONENT_GROUPS]);
+ return this.getComponentDataByFieldsName(component.componentType, component.uniqueId, [COMPONENT_FIELDS.COMPONENT_INSTANCES_RELATION, COMPONENT_FIELDS.COMPONENT_INSTANCES, COMPONENT_FIELDS.COMPONENT_NON_EXCLUDED_POLICIES, COMPONENT_FIELDS.COMPONENT_NON_EXCLUDED_GROUPS]);
+ }
+
+ getComponentResourcePropertiesData(component:Component):Observable<ComponentGenericResponse> {
+ return this.getComponentDataByFieldsName(component.componentType, component.uniqueId, [COMPONENT_FIELDS.COMPONENT_INSTANCES, COMPONENT_FIELDS.COMPONENT_POLICIES, COMPONENT_FIELDS.COMPONENT_NON_EXCLUDED_GROUPS]);
}
getComponentResourceInstances(component:Component):Observable<ComponentGenericResponse> {
@@ -171,6 +179,15 @@
})
}
+ restoreComponent(componentType:string, componentId:string){
+ return this.http.post(this.baseUrl + this.getServerTypeUrl(componentType) + componentId + '/restore', {})
+ }
+
+ archiveComponent(componentType:string, componentId:string){
+ return this.http.post(this.baseUrl + this.getServerTypeUrl(componentType) + componentId + '/archive', {})
+ }
+
+
deleteInput(component:Component, input:InputBEModel):Observable<InputBEModel> {
return this.http.delete(this.baseUrl + component.getTypeUrl() + component.uniqueId + '/delete/' + input.uniqueId + '/input')
@@ -198,5 +215,19 @@
return res.json();
});
}
+
+ getDependencies(componentType:string, componentId: string):Observable<Array<IDependenciesServerResponse>> {
+ return this.http.get(this.baseUrl + this.getServerTypeUrl(componentType) + componentId + '/dependencies')
+ .map((res:Response) => {
+ return res.json();
+ });
+ }
+
+ automatedUpgrade(componentType:string, componentId: string, componentsIdsToUpgrade:Array<IAutomatedUpgradeRequestObj>):Observable<AutomatedUpgradeGenericResponse> {
+ return this.http.post(this.baseUrl + this.getServerTypeUrl(componentType) + componentId + '/automatedupgrade', componentsIdsToUpgrade)
+ .map((res:Response) => {
+ return res.json();
+ });
+ }
}
diff --git a/catalog-ui/src/app/ng2/services/component-services/service.service.ts b/catalog-ui/src/app/ng2/services/component-services/service.service.ts
index 0439f20..15e624b 100644
--- a/catalog-ui/src/app/ng2/services/component-services/service.service.ts
+++ b/catalog-ui/src/app/ng2/services/component-services/service.service.ts
@@ -126,7 +126,7 @@
}
getComponentCompositionData(component:Component):Observable<ComponentGenericResponse> {
- return this.getComponentDataByFieldsName(component.componentType, component.uniqueId, [COMPONENT_FIELDS.COMPONENT_INSTANCES_RELATION, COMPONENT_FIELDS.COMPONENT_INSTANCES, SERVICE_FIELDS.FORWARDING_PATHS]);
+ return this.getComponentDataByFieldsName(component.componentType, component.uniqueId, [COMPONENT_FIELDS.COMPONENT_INSTANCES_RELATION, COMPONENT_FIELDS.COMPONENT_INSTANCES, SERVICE_FIELDS.FORWARDING_PATHS, COMPONENT_FIELDS.COMPONENT_NON_EXCLUDED_POLICIES, COMPONENT_FIELDS.COMPONENT_NON_EXCLUDED_GROUPS]);
}
protected analyzeComponentDataResponse(res: Response):ComponentGenericResponse {
diff --git a/catalog-ui/src/app/ng2/services/config.service.ts b/catalog-ui/src/app/ng2/services/config.service.ts
index a9a4e86..1774a66 100644
--- a/catalog-ui/src/app/ng2/services/config.service.ts
+++ b/catalog-ui/src/app/ng2/services/config.service.ts
@@ -38,7 +38,7 @@
constructor(private http: Http, @Inject(SdcConfigToken) private sdcConfig:ISdcConfig) {
this.api = this.sdcConfig.api;
- this.baseUrl = this.sdcConfig.api.root + this.sdcConfig.api.component_api_root;
+ this.baseUrl = this.api.root + this.sdcConfig.api.component_api_root;
}
loadValidationConfiguration(): Promise<ValidationConfiguration> {
diff --git a/catalog-ui/src/app/ng2/services/groups.service.ts b/catalog-ui/src/app/ng2/services/groups.service.ts
new file mode 100644
index 0000000..e3b3d85
--- /dev/null
+++ b/catalog-ui/src/app/ng2/services/groups.service.ts
@@ -0,0 +1,78 @@
+import {IZoneInstanceAssignment} from '../../models/graph/zones/zone-instance';
+import {Injectable, Inject} from "@angular/core";
+import {Observable} from "rxjs/Observable";
+import {HttpService} from "./http.service";
+import {SdcConfigToken, ISdcConfig} from "../config/sdc-config.config";
+import {GroupInstance} from '../../models/graph/zones/group-instance';
+import {UiBaseObject} from "../../models/ui-models/ui-base-object";
+import {IZoneService} from "../../models/graph/zones/zone";
+
+@Injectable()
+export class GroupsService implements IZoneService {
+
+ protected baseUrl;
+
+ private mapApiDirections = {
+ 'RESOURCE': 'resources',
+ 'SERVICE': 'services'
+ }
+
+ constructor(private http:HttpService, @Inject(SdcConfigToken) sdcConfig:ISdcConfig) {
+ this.baseUrl = sdcConfig.api.root;
+ }
+
+ public createGroupInstance(componentType:string, componentUniqueId:string, groupType:string) {
+ return this.http.post(this.baseUrl + '/v1/catalog/' + this.mapApiDirections[componentType.toUpperCase()] + '/' + componentUniqueId + '/groups/' + groupType, {}).map(resp => {
+ return resp.json();
+ });
+ };
+
+ public addGroupMember(topologyTemplateType:string, topologyTemplateId:string, group:GroupInstance, memberId:string) {
+ let members:Array<string> = Object.assign({}, group.members);
+ members.push(memberId);
+ return this.updateGroupMembers(topologyTemplateType, topologyTemplateId, group.uniqueId, members);
+ }
+
+ public deleteGroupMember(topologyTemplateType:string, topologyTemplateId:string, group:GroupInstance, memberId:string) {
+ let _members:Array<string> = angular.copy(group.members);
+ _members =_.without(_members, memberId);
+ return this.updateGroupMembers(topologyTemplateType, topologyTemplateId, group.uniqueId, _members);
+ }
+
+ public updateGroupMembers(topologyTemplateType:string, topologyTemplateId:string, groupId:string, members:Array<string>):Observable<Array<string>> {
+ return this.http.post(this.baseUrl + '/v1/catalog/' + this.mapApiDirections[topologyTemplateType.toUpperCase()] + '/' + topologyTemplateId + '/groups/' + groupId + '/members', members)
+ .map(response => response.json());
+ }
+
+ public updateMembers(topologyTemplateType:string, topologyTemplateId:string, groupId:string, members:Array<UiBaseObject>):Observable<Array<string>> {
+ let membersIds:Array<string> = members.map(member => member.uniqueId);
+ return this.updateGroupMembers(topologyTemplateType, topologyTemplateId, groupId, membersIds);
+ }
+
+ public getSpecificGroup(topologyTemplateType:string, topologyTemplateId:string, groupId:string):Observable<GroupInstance> {
+ return this.http.get(this.baseUrl + '/v1/catalog/' + this.mapApiDirections[topologyTemplateType.toUpperCase()] + '/' + topologyTemplateId + '/groups/' + groupId)
+ .map(res => {
+ return new GroupInstance(res.json());
+ });
+ }
+
+ public updateName(topologyTemplateType:string, topologyTemplateId:string, groupId:string, newName:string):Observable<GroupInstance> {
+ return this.http.put(this.baseUrl + '/v1/catalog/' + this.mapApiDirections[topologyTemplateType.toUpperCase()] + '/' + topologyTemplateId + '/groups/' + groupId, {name: newName}).map(resp => {
+ return resp.json();
+ });
+ };
+
+ public deleteGroup(topologyTemplateType:string, topologyTemplateId:string, groupId:string) {
+ return this.http.delete(this.baseUrl + '/v1/catalog/' + this.mapApiDirections[topologyTemplateType.toUpperCase()] + '/' + topologyTemplateId + '/groups/' + groupId).map(resp => {
+ return resp.json();
+ });
+ };
+
+ public updateZoneInstanceAssignments(topologyTemplateType:string, topologyTemplateId:string, policyId:string, members:Array<IZoneInstanceAssignment>):Observable<any> {
+ return this.updateMembers(topologyTemplateType, topologyTemplateId, policyId, members);
+ };
+
+ public deleteZoneInstance(topologyTemplateType:string, topologyTemplateId:string, policyId:string):Observable<any> {
+ return this.deleteGroup(topologyTemplateType, topologyTemplateId, policyId);
+ };
+}
\ No newline at end of file
diff --git a/catalog-ui/src/app/ng2/services/modal.service.ts b/catalog-ui/src/app/ng2/services/modal.service.ts
index 4e86d6a..a8f1b99 100644
--- a/catalog-ui/src/app/ng2/services/modal.service.ts
+++ b/catalog-ui/src/app/ng2/services/modal.service.ts
@@ -24,6 +24,10 @@
this.createCustomModal(modalModel).instance.open();
}
+ public openErrorModal = (closeButtonText?: string, errorMessage?: string):void => {
+ let errorModal = this.createErrorModal(closeButtonText, errorMessage);
+ errorModal.instance.open();
+ };
/**
* Shortcut method to open a basic modal with title, message, and an action button with callback, as well as close button.
@@ -77,7 +81,7 @@
return wizardInstance;
}
-
+
public closeCurrentModal = () => {
if (!this.currentModal) return;
this.currentModal.instance.close();
@@ -102,3 +106,5 @@
}
+
+
diff --git a/catalog-ui/src/app/ng2/services/policies.service.ts b/catalog-ui/src/app/ng2/services/policies.service.ts
index 2b564b8..3675a7b 100644
--- a/catalog-ui/src/app/ng2/services/policies.service.ts
+++ b/catalog-ui/src/app/ng2/services/policies.service.ts
@@ -18,32 +18,107 @@
* ============LICENSE_END=========================================================
*/
-import { Injectable, Inject } from "@angular/core";
-import { Headers } from "@angular/http";
-import { Observable } from "rxjs/Observable";
-import { HttpService } from "./http.service";
-import { Cookie2Service } from "./cookie.service";
+import {Injectable, Inject} from "@angular/core";
+import {Observable} from "rxjs/Observable";
+import {HttpService} from "./http.service";
import {SdcConfigToken, ISdcConfig} from "../config/sdc-config.config";
+import {PolicyInstance, PolicyTargetsRequest} from '../../models/graph/zones/policy-instance';
+import {IZoneInstanceAssignment} from "../../models/graph/zones/zone-instance";
+import {IZoneService} from "../../models/graph/zones/zone";
+import {TargetUiObject} from "../../models/ui-models/ui-target-object";
+import {TargetOrMemberType} from "../../utils/constants";
@Injectable()
-export class PoliciesService {
+export class PoliciesService implements IZoneService {
protected baseUrl;
private mapApiDirections = {
- 'RESOURCE':'resources',
- 'SERVICE':'services'
+ 'RESOURCE': 'resources',
+ 'SERVICE': 'services'
}
- constructor(private http: HttpService, @Inject(SdcConfigToken) sdcConfig:ISdcConfig) {
- this.baseUrl = sdcConfig.api.root ;
+ constructor(private http:HttpService, @Inject(SdcConfigToken) sdcConfig:ISdcConfig) {
+ this.baseUrl = sdcConfig.api.root;
}
- public createPolicyInstance(entityType:string, id:string, policyType:string) {
- return this.http.post(this.baseUrl + '/v1/catalog/' + this.mapApiDirections[entityType] + '/' + id +'/policies/' + policyType, {}).map(resp => {
- return resp.json();
+ public createPolicyInstance(topologyTemplateType:string, topologyTemplateId:string, policyType:string) {
+ return this.http.post(this.baseUrl + '/v1/catalog/' + this.mapApiDirections[topologyTemplateType.toUpperCase()] + '/' + topologyTemplateId + '/policies/' + policyType, {}).map(resp => {
+ return resp.json();
});
}
+ public addPolicyTarget(topologyTemplateType:string, topologyTemplateId:string, policy:PolicyInstance, targetId:string, targetType:TargetOrMemberType) {
+ let _targets:Array<string>;
+ let _members:Array<string>;
+
+ if (targetType === TargetOrMemberType.COMPONENT_INSTANCES) {
+ _targets = angular.copy(policy.targets.COMPONENT_INSTANCES);
+ _targets.push(targetId);
+ } else if (targetType === TargetOrMemberType.GROUPS) {
+ _members = angular.copy(policy.targets.GROUPS);
+ _members.push(targetId);
+ }
+ let policyTargetRequest:PolicyTargetsRequest = new PolicyTargetsRequest(_members, _targets);
+ return this.updatePolicyTargets(topologyTemplateType, topologyTemplateId, policy.uniqueId, policyTargetRequest);
+ }
+
+ public deletePolicyTarget(topologyTemplateType:string, topologyTemplateId:string, policy:PolicyInstance, targetId:string, targetType:TargetOrMemberType): Observable<PolicyInstance> {
+ let _targets:Array<string> = angular.copy(policy.targets.COMPONENT_INSTANCES);
+ let _members:Array<string> = angular.copy(policy.targets.GROUPS);
+ if (targetType === TargetOrMemberType.COMPONENT_INSTANCES) {
+ _targets = _.without(_targets, targetId);
+ } else if (targetType === TargetOrMemberType.GROUPS) {
+ _members = _.without(_members, targetId);
+ }
+ let policyTargetRequest:PolicyTargetsRequest = new PolicyTargetsRequest(_members, _targets);
+ return this.updatePolicyTargets(topologyTemplateType, topologyTemplateId, policy.uniqueId, policyTargetRequest);
+ }
+
+ public updatePolicyTargets(topologyTemplateType:string, topologyTemplateId:string, policyId:string, targets:PolicyTargetsRequest): Observable<PolicyInstance> {
+ return this.http.post(this.baseUrl + '/v1/catalog/' + this.mapApiDirections[topologyTemplateType.toUpperCase()] + '/' + topologyTemplateId + '/policies/' + policyId + '/targets', targets.requestItems)
+ .map(response => new PolicyInstance(response.json()));
+ }
+
+ public updateTargets(topologyTemplateType:string, topologyTemplateId:string, policyId:string, targets:Array<TargetUiObject>):Observable<PolicyInstance> {
+ let instances:Array<string> = _.filter(targets, (target:TargetUiObject)=> {
+ return target.type === TargetOrMemberType.COMPONENT_INSTANCES;
+ }).map(target => target.uniqueId);
+
+ let groups:Array<string> = _.filter(targets, (target:TargetUiObject)=> {
+ return target.type === TargetOrMemberType.GROUPS;
+ }).map(target => target.uniqueId);
+
+ let policyTargetRequest:PolicyTargetsRequest = new PolicyTargetsRequest(groups, instances);
+ return this.updatePolicyTargets(topologyTemplateType, topologyTemplateId, policyId, policyTargetRequest);
+ }
+
+ public getSpecificPolicy(topologyTemplateType:string, topologyTemplateId:string, policyId:string):Observable<PolicyInstance> {
+ return this.http.get(this.baseUrl + '/v1/catalog/' + this.mapApiDirections[topologyTemplateType.toUpperCase()] + '/' + topologyTemplateId + '/policies/' + policyId)
+ .map(res => {
+ return new PolicyInstance(res.json());
+ });
+ }
+
+ public updateName(topologyTemplateType:string, topologyTemplateId:string, policyId:string, newName:string):Observable<any> {
+ return this.http.put(this.baseUrl + '/v1/catalog/' + this.mapApiDirections[topologyTemplateType.toUpperCase()] + '/' + topologyTemplateId + '/policies/' + policyId, {name: newName}).map(res => {
+ return res.json();
+ });
+ };
+
+ public deletePolicy(topologyTemplateType:string, topologyTemplateId:string, policyId:string) {
+ return this.http.delete(this.baseUrl + '/v1/catalog/' + this.mapApiDirections[topologyTemplateType.toUpperCase()] + '/' + topologyTemplateId + '/policies/' + policyId).map(resp => {
+ return resp.json();
+ });
+ };
+
+ public updateZoneInstanceAssignments(topologyTemplateType:string, topologyTemplateId:string, policyId:string, targets:Array<IZoneInstanceAssignment>):Observable<PolicyInstance>{
+ return this.updateTargets(topologyTemplateType, topologyTemplateId, policyId, targets);
+ };
+
+ public deleteZoneInstance(topologyTemplateType:string, topologyTemplateId:string, policyId:string):Observable<any> {
+ return this.deletePolicy(topologyTemplateType, topologyTemplateId, policyId);
+ };
+
}
diff --git a/catalog-ui/src/app/ng2/services/responses/automated-upgrade-response.ts b/catalog-ui/src/app/ng2/services/responses/automated-upgrade-response.ts
new file mode 100644
index 0000000..feac868
--- /dev/null
+++ b/catalog-ui/src/app/ng2/services/responses/automated-upgrade-response.ts
@@ -0,0 +1,16 @@
+/**
+ * Created by ob0695 on 4/29/2018.
+ */
+
+export class AutomatedUpgradeStatusResponse {
+ name:string;
+ status:string;
+ uniqueId:string;
+ version:string;
+}
+
+export class AutomatedUpgradeGenericResponse {
+ error:string;
+ status:string;
+ componentToUpgradeStatus:Array<AutomatedUpgradeStatusResponse>;
+}
\ No newline at end of file
diff --git a/catalog-ui/src/app/ng2/services/responses/component-generic-response.ts b/catalog-ui/src/app/ng2/services/responses/component-generic-response.ts
index 5036a10..a77133e 100644
--- a/catalog-ui/src/app/ng2/services/responses/component-generic-response.ts
+++ b/catalog-ui/src/app/ng2/services/responses/component-generic-response.ts
@@ -28,6 +28,7 @@
import {Serializable} from "../utils/serializable";
import {PropertyBEModel} from "../../../models/properties-inputs/property-be-model";
import { PolicyInstance } from "app/models/graph/zones/policy-instance";
+import { GroupInstance } from "../../../models/graph/zones/group-instance";
export class ComponentGenericResponse implements Serializable<ComponentGenericResponse> {
@@ -45,7 +46,8 @@
public properties:Array<PropertyModel>;
public attributes:Array<AttributeModel>;
public policies:Array<PolicyInstance>;
- public groups:Array<Module>;
+ public groupInstances: Array<GroupInstance>;
+ public modules:Array<Module>;
public interfaces:any;
public interfaceOperations:Array<OperationModel>;
public additionalInformation:any;
@@ -96,7 +98,8 @@
this.metadata = new ComponentMetadata().deserialize(response.metadata);
}
if(response.groups) {
- this.groups = CommonUtils.initModules(response.groups);
+ this.modules = CommonUtils.initModules(response.groups);
+ this.groupInstances = CommonUtils.initGroups(response.groups)
}
if(response.policies) {
this.policies = CommonUtils.initPolicies(response.policies);
diff --git a/catalog-ui/src/app/ng2/services/responses/dependencies-server-response.ts b/catalog-ui/src/app/ng2/services/responses/dependencies-server-response.ts
new file mode 100644
index 0000000..be8aaea
--- /dev/null
+++ b/catalog-ui/src/app/ng2/services/responses/dependencies-server-response.ts
@@ -0,0 +1,14 @@
+import { state } from '@angular/core';
+/**
+ * Created by ob0695 on 4/23/2018.
+ */
+export interface IDependenciesServerResponse {
+ icon: string;
+ name: string;
+ type: string;
+ uniqueId: string;
+ version: string;
+ state: string;
+ dependencies: Array<IDependenciesServerResponse>;
+ instanceNames: Array<string>;
+}
\ No newline at end of file
diff --git a/catalog-ui/src/app/ng2/services/window.service.ts b/catalog-ui/src/app/ng2/services/window.service.ts
new file mode 100644
index 0000000..0a11166
--- /dev/null
+++ b/catalog-ui/src/app/ng2/services/window.service.ts
@@ -0,0 +1,8 @@
+import {Injectable} from "@angular/core";
+
+@Injectable()
+export class WindowRef {
+ get nativeWindow(): any {
+ return window;
+ }
+}
diff --git a/catalog-ui/src/app/ng2/shared/multiline-ellipsis/multiline-ellipsis.component.html b/catalog-ui/src/app/ng2/shared/multiline-ellipsis/multiline-ellipsis.component.html
new file mode 100644
index 0000000..c9f59f0
--- /dev/null
+++ b/catalog-ui/src/app/ng2/shared/multiline-ellipsis/multiline-ellipsis.component.html
@@ -0,0 +1,6 @@
+<div class="multiline-ellipsis-container" [ngClass]="className" [ngStyle]="stylesContainer" #multilineEllipsisContainer>
+ <div class="multiline-ellipsis-content" [ngStyle]="stylesContent" #multilineEllipsisContent>
+ <ng-content></ng-content>
+ <div class="multiline-ellipsis-dots" [ngStyle]="stylesDots"></div>
+ </div>
+</div>
\ No newline at end of file
diff --git a/catalog-ui/src/app/ng2/shared/multiline-ellipsis/multiline-ellipsis.component.less b/catalog-ui/src/app/ng2/shared/multiline-ellipsis/multiline-ellipsis.component.less
new file mode 100644
index 0000000..c616d37
--- /dev/null
+++ b/catalog-ui/src/app/ng2/shared/multiline-ellipsis/multiline-ellipsis.component.less
@@ -0,0 +1,25 @@
+.multiline-ellipsis-container {
+ position: relative;
+ display: block;
+ overflow: hidden;
+ white-space: normal;
+ //max-height: @num_lines * @line_height;
+
+ .multiline-ellipsis-content {
+ word-break: break-all;
+ position: relative;
+ //max-height: (@num_lines + 1) * @line_height;
+
+ .multiline-ellipsis-dots {
+ display: block;
+ position: absolute;
+ right: 0;
+ //top: calc(#{@num_lines * 2} - 100%);
+
+ &::before {
+ display: block;
+ content: '...';
+ }
+ }
+ }
+}
diff --git a/catalog-ui/src/app/ng2/shared/multiline-ellipsis/multiline-ellipsis.component.ts b/catalog-ui/src/app/ng2/shared/multiline-ellipsis/multiline-ellipsis.component.ts
new file mode 100644
index 0000000..68cfedb
--- /dev/null
+++ b/catalog-ui/src/app/ng2/shared/multiline-ellipsis/multiline-ellipsis.component.ts
@@ -0,0 +1,58 @@
+import {Component, OnChanges, AfterViewChecked, ViewChild, ElementRef, Input, Output, SimpleChanges, EventEmitter} from "@angular/core";
+import {WindowRef} from "../../services/window.service";
+
+@Component({
+ selector: 'multiline-ellipsis',
+ templateUrl: 'multiline-ellipsis.component.html',
+ styleUrls: ['multiline-ellipsis.component.less']
+})
+export class MultilineEllipsisComponent implements OnChanges, AfterViewChecked {
+
+ @Input() public lines: number;
+ @Input() public lineHeight: string;
+ @Input() public className: string;
+ @Output() public hasEllipsisChanged: EventEmitter<boolean>;
+
+ @ViewChild('multilineEllipsisContainer') public elmContainer: ElementRef;
+ @ViewChild('multilineEllipsisContent') public elmContent: ElementRef;
+
+ public stylesContainer: {[key: string]: string};
+ public stylesContent: {[key: string]: string};
+ public stylesDots: {[key: string]: string};
+
+ private hasEllipsis: boolean;
+
+ public constructor(private windowRef: WindowRef) {
+ this.hasEllipsisChanged = new EventEmitter<boolean>();
+ }
+
+ public ngOnChanges(changes: SimpleChanges) {
+ this.prepareStyles()
+ }
+
+ public ngAfterViewChecked() {
+ const hasEllipsis = (this.elmContainer.nativeElement.offsetHeight < this.elmContent.nativeElement.offsetHeight);
+ if (hasEllipsis !== this.hasEllipsis) {
+ this.hasEllipsis = hasEllipsis;
+ this.hasEllipsisChanged.emit(this.hasEllipsis);
+ }
+ }
+
+ private prepareStyles() {
+ const lineHeight = this.lineHeight || this.getLineHeight();
+ this.stylesContainer = {
+ 'max-height': `calc(${this.lines} * ${lineHeight})`
+ };
+ this.stylesContent = {
+ 'max-height': `calc(${this.lines + 1} * ${lineHeight})`
+ };
+ this.stylesDots = {
+ 'top': `calc(${2 * this.lines} * ${lineHeight} - 100%)`
+ };
+ }
+
+ private getLineHeight() {
+ return this.windowRef.nativeWindow.getComputedStyle(this.elmContainer.nativeElement)['line-height'];
+ }
+
+}
diff --git a/catalog-ui/src/app/ng2/shared/multiline-ellipsis/multiline-ellipsis.module.ts b/catalog-ui/src/app/ng2/shared/multiline-ellipsis/multiline-ellipsis.module.ts
new file mode 100644
index 0000000..24ed7b3
--- /dev/null
+++ b/catalog-ui/src/app/ng2/shared/multiline-ellipsis/multiline-ellipsis.module.ts
@@ -0,0 +1,11 @@
+import {NgModule} from '@angular/core';
+import {CommonModule} from '@angular/common';
+import {MultilineEllipsisComponent} from './multiline-ellipsis.component';
+
+@NgModule({
+ declarations: [MultilineEllipsisComponent],
+ imports: [CommonModule],
+ exports: [MultilineEllipsisComponent],
+ entryComponents: [MultilineEllipsisComponent]
+})
+export class MultilineEllipsisModule {}
diff --git a/catalog-ui/src/app/ng2/utils/ng1-upgraded-provider.ts b/catalog-ui/src/app/ng2/utils/ng1-upgraded-provider.ts
index c005efc..fcb21c0 100644
--- a/catalog-ui/src/app/ng2/utils/ng1-upgraded-provider.ts
+++ b/catalog-ui/src/app/ng2/utils/ng1-upgraded-provider.ts
@@ -21,12 +21,14 @@
/**
* Created by rc2122 on 4/6/2017.
*/
-import {DataTypesService} from "../../services/data-types-service";
+import { DataTypesService } from "../../services/data-types-service";
import ICacheObject = angular.ICacheObject;
-import {SharingService} from "../../services/sharing-service";
-import {CookieService} from "../../services/cookie-service";
-import {CacheService} from "../../services/cache-service";
-import {EventListenerService} from "app/services/event-listener-service";
+import { SharingService } from "../../services/sharing-service";
+import { CookieService } from "../../services/cookie-service";
+import { CacheService } from "../../services/cache-service";
+import {ComponentFactory} from "../../utils/component-factory"
+import { EventListenerService } from "app/services/event-listener-service";
+import { ModalsHandler } from "app/utils";
import IScope = angular.IScope;
/** Services we need to upgrade from angular1 to angular2 - in the future we need to rewrite them all to angular2 **/
@@ -39,6 +41,10 @@
return cacheObj.get('Sdc.Services.SharingService');
}
+export function componentServiceFactory(cacheObj: ICacheObject) {
+ return cacheObj.get('Sdc.Services.ComponentFactory');
+}
+
export function cookieServiceFactory(cacheObj: ICacheObject) {
return cacheObj.get('Sdc.Services.CookieService');
}
@@ -47,14 +53,14 @@
return cacheObj.get('$state');
}
-export function scopeServiceFactory(cacheObj: ICacheObject) {
- return cacheObj.get('$scope');
-}
-
export function stateParamsServiceFactory(cacheObj: ICacheObject) {
return cacheObj.get('$stateParams');
}
+export function scopeServiceFactory(cacheObj: ICacheObject) {
+ return cacheObj.get('$scope');
+}
+
export function cacheServiceFactory(cacheObj: ICacheObject) {
return cacheObj.get('Sdc.Services.CacheService');
}
@@ -67,6 +73,18 @@
return cacheObj.get('Notification');
}
+
+export const ComponentFactoryProvider = {
+ provide: ComponentFactory,
+ useFactory: componentServiceFactory,
+ deps: ['$injector']
+};
+
+
+export function ModalsHandlerFactory(cacheObj: ICacheObject) {
+ return cacheObj.get('ModalsHandler');
+}
+
export const DataTypesServiceProvider = {
provide: DataTypesService,
useFactory: dataTypesServiceFactory,
@@ -93,7 +111,7 @@
deps: ['$injector']
};
-export const ScopeServiceFactory= {
+export const ScopeServiceFactory = {
provide: '$scope',
useFactory: scopeServiceFactory,
deps: ['$injector']
@@ -104,7 +122,6 @@
useFactory: stateParamsServiceFactory,
deps: ['$injector']
};
-
export const CacheServiceProvider = {
provide: CacheService,
useFactory: cacheServiceFactory,
@@ -122,3 +139,9 @@
useFactory: notificationServiceFactory,
deps: ['$injector']
};
+
+export const ModalsHandlerProvider = {
+ provide: ModalsHandler,
+ useFactory: ModalsHandlerFactory,
+ deps: ['$injector']
+}