aboutsummaryrefslogtreecommitdiffstats
path: root/vid-webpack-master/src/app
diff options
context:
space:
mode:
authorSonsino, Ofir (os0695) <os0695@intl.att.com>2018-07-10 15:57:37 +0300
committerSonsino, Ofir (os0695) <os0695@intl.att.com>2018-07-10 15:57:37 +0300
commitff76b5ed0aa91d5fdf9dc4f95e8b20f91ed9d072 (patch)
treeaae42404a93fdffdd16ff050eaa28129959f7577 /vid-webpack-master/src/app
parentc72d565bb58226b20625b2bce5f0019046bee649 (diff)
New Angular UI from 1806
Change-Id: I39c160db0e0a6ec2e587ccf007ee1b23c6a08666 Issue-ID: VID-208 Signed-off-by: Sonsino, Ofir (os0695) <os0695@intl.att.com>
Diffstat (limited to 'vid-webpack-master/src/app')
-rw-r--r--vid-webpack-master/src/app/app.component.e2e-spec.js27
-rw-r--r--vid-webpack-master/src/app/app.component.html6
-rw-r--r--vid-webpack-master/src/app/app.component.scss24
-rw-r--r--vid-webpack-master/src/app/app.component.ts28
-rw-r--r--vid-webpack-master/src/app/app.module.ts79
-rw-r--r--vid-webpack-master/src/app/app.routing.ts40
-rw-r--r--vid-webpack-master/src/app/browseSdc/browseSdc.component.html26
-rw-r--r--vid-webpack-master/src/app/browseSdc/browseSdc.component.scss59
-rw-r--r--vid-webpack-master/src/app/browseSdc/browseSdc.component.ts176
-rw-r--r--vid-webpack-master/src/app/browseSdc/browseSdc.module.ts35
-rw-r--r--vid-webpack-master/src/app/browseSdc/previous-versions/previous-versions.component.ts29
-rw-r--r--vid-webpack-master/src/app/browseSdc/previous-versions/previous-versions.css4
-rw-r--r--vid-webpack-master/src/app/browseSdc/previous-versions/previous-versions.html18
-rw-r--r--vid-webpack-master/src/app/browseSdc/vid-table/vid-table.component.html26
-rw-r--r--vid-webpack-master/src/app/browseSdc/vid-table/vid-table.component.scss40
-rw-r--r--vid-webpack-master/src/app/browseSdc/vid-table/vid-table.component.ts59
-rw-r--r--vid-webpack-master/src/app/components/dynamic-inputs/dynamic-inputs.component.ts80
-rw-r--r--vid-webpack-master/src/app/components/dynamic-inputs/dynamic-inputs.html22
-rw-r--r--vid-webpack-master/src/app/components/dynamic-inputs/dynamic-inputs.scss58
-rw-r--r--vid-webpack-master/src/app/components/form-async/form-async.component.ts80
-rw-r--r--vid-webpack-master/src/app/components/form-async/form-async.style.scss15
-rw-r--r--vid-webpack-master/src/app/components/form-async/form-async.template.html67
-rw-r--r--vid-webpack-master/src/app/components/instance-popup/instance-popup.components.ts9
-rw-r--r--vid-webpack-master/src/app/components/service-popup/service-instance-details/service-instance-details.component.ts238
-rw-r--r--vid-webpack-master/src/app/components/service-popup/service-instance-details/service-instance-details.html168
-rw-r--r--vid-webpack-master/src/app/components/service-popup/service-instance-details/service-instance-details.scss64
-rw-r--r--vid-webpack-master/src/app/components/service-popup/service-instance-details/service-instance-details.service.spec.ts26
-rw-r--r--vid-webpack-master/src/app/components/service-popup/service-instance-details/service-instance-details.service.ts22
-rw-r--r--vid-webpack-master/src/app/components/service-popup/service-instance-details/servicePopupDataModel.ts32
-rw-r--r--vid-webpack-master/src/app/components/service-popup/service-popup.component.ts144
-rw-r--r--vid-webpack-master/src/app/components/service-popup/service-popup.html52
-rw-r--r--vid-webpack-master/src/app/components/service-popup/service-popup.scss185
-rw-r--r--vid-webpack-master/src/app/components/service-popup/service-popup.service.spec.ts138
-rw-r--r--vid-webpack-master/src/app/components/service-popup/service-popup.service.ts33
-rw-r--r--vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnf-instance-details.component.ts275
-rw-r--r--vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnf-instance-details.html114
-rw-r--r--vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnf-instance-details.scss64
-rw-r--r--vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnf-instance-details.service.spec.ts241
-rw-r--r--vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnf-instance-details.service.ts64
-rw-r--r--vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnfPopupDataModel.ts26
-rw-r--r--vid-webpack-master/src/app/components/vnf-popup/vnf-popup-service.ts55
-rw-r--r--vid-webpack-master/src/app/components/vnf-popup/vnf-popup.components.ts190
-rw-r--r--vid-webpack-master/src/app/components/vnf-popup/vnf-popup.html54
-rw-r--r--vid-webpack-master/src/app/components/vnf-popup/vnf-popup.scss185
-rw-r--r--vid-webpack-master/src/app/components/vnf-popup/vnf-popup.service.spec.ts827
-rw-r--r--vid-webpack-master/src/app/configuration/vid.configuration.ts98
-rw-r--r--vid-webpack-master/src/app/drawingBoard/available-models-tree/available-models-tree.component.html35
-rw-r--r--vid-webpack-master/src/app/drawingBoard/available-models-tree/available-models-tree.component.scss398
-rw-r--r--vid-webpack-master/src/app/drawingBoard/available-models-tree/available-models-tree.component.ts166
-rw-r--r--vid-webpack-master/src/app/drawingBoard/available-models-tree/available-models-tree.service.spec.ts450
-rw-r--r--vid-webpack-master/src/app/drawingBoard/available-models-tree/available-models-tree.service.ts36
-rw-r--r--vid-webpack-master/src/app/drawingBoard/drawing-board-header/drawing-board-header.component.html33
-rw-r--r--vid-webpack-master/src/app/drawingBoard/drawing-board-header/drawing-board-header.component.scss95
-rw-r--r--vid-webpack-master/src/app/drawingBoard/drawing-board-header/drawing-board-header.component.ts119
-rw-r--r--vid-webpack-master/src/app/drawingBoard/drawing-board-header/tmp_instansiate_request.ts52
-rw-r--r--vid-webpack-master/src/app/drawingBoard/drawing-board-tree/drawing-board-tree.component.ts133
-rw-r--r--vid-webpack-master/src/app/drawingBoard/drawing-board-tree/drawing-board-tree.html42
-rw-r--r--vid-webpack-master/src/app/drawingBoard/drawing-board-tree/drawing-board-tree.scss274
-rw-r--r--vid-webpack-master/src/app/drawingBoard/drawingBoard.module.ts41
-rw-r--r--vid-webpack-master/src/app/drawingBoard/service-planning/service-planning.component.html13
-rw-r--r--vid-webpack-master/src/app/drawingBoard/service-planning/service-planning.component.scss16
-rw-r--r--vid-webpack-master/src/app/drawingBoard/service-planning/service-planning.component.ts77
-rw-r--r--vid-webpack-master/src/app/factories/models/requestDetails.model.ts126
-rw-r--r--vid-webpack-master/src/app/factories/mso.factory.spec.ts319
-rw-r--r--vid-webpack-master/src/app/factories/mso.factory.ts92
-rw-r--r--vid-webpack-master/src/app/global.actions.ts23
-rw-r--r--vid-webpack-master/src/app/global.reducer.ts29
-rw-r--r--vid-webpack-master/src/app/healthStatus/health-status.component.html36
-rw-r--r--vid-webpack-master/src/app/healthStatus/health-status.component.scss187
-rw-r--r--vid-webpack-master/src/app/healthStatus/health-status.component.ts42
-rw-r--r--vid-webpack-master/src/app/home/home.component.e2e-spec.js13
-rw-r--r--vid-webpack-master/src/app/home/home.component.html3
-rw-r--r--vid-webpack-master/src/app/home/home.component.scss4
-rw-r--r--vid-webpack-master/src/app/home/home.component.ts30
-rw-r--r--vid-webpack-master/src/app/instantiationStatus/InstantiationStatus.module.ts33
-rw-r--r--vid-webpack-master/src/app/instantiationStatus/auditInfoModal/auditInfoModal.component.html84
-rw-r--r--vid-webpack-master/src/app/instantiationStatus/auditInfoModal/auditInfoModal.component.scss159
-rw-r--r--vid-webpack-master/src/app/instantiationStatus/auditInfoModal/auditInfoModal.component.service.ts0
-rw-r--r--vid-webpack-master/src/app/instantiationStatus/auditInfoModal/auditInfoModal.component.ts83
-rw-r--r--vid-webpack-master/src/app/instantiationStatus/instantiationStatus.component.html100
-rw-r--r--vid-webpack-master/src/app/instantiationStatus/instantiationStatus.component.scss277
-rw-r--r--vid-webpack-master/src/app/instantiationStatus/instantiationStatus.component.service.spec.ts278
-rw-r--r--vid-webpack-master/src/app/instantiationStatus/instantiationStatus.component.service.ts75
-rw-r--r--vid-webpack-master/src/app/instantiationStatus/instantiationStatus.component.spec.ts88
-rw-r--r--vid-webpack-master/src/app/instantiationStatus/instantiationStatus.component.ts145
-rw-r--r--vid-webpack-master/src/app/modules/inputs.module.ts20
-rw-r--r--vid-webpack-master/src/app/service.actions.ts197
-rw-r--r--vid-webpack-master/src/app/service.reducer.spec.ts286
-rw-r--r--vid-webpack-master/src/app/service.reducer.ts214
-rw-r--r--vid-webpack-master/src/app/services/aaiService/aai.actions.ts75
-rw-r--r--vid-webpack-master/src/app/services/aaiService/aai.epics.ts81
-rw-r--r--vid-webpack-master/src/app/services/aaiService/aai.service.ts189
-rw-r--r--vid-webpack-master/src/app/services/aaiService/responseInterfaces/getAicZonesResponseInterface.ts3
-rw-r--r--vid-webpack-master/src/app/services/aaiService/responseInterfaces/getCategoryParamsResponseInterface.ts10
-rw-r--r--vid-webpack-master/src/app/services/aaiService/responseInterfaces/getServiceModelResponseInterface.ts5
-rw-r--r--vid-webpack-master/src/app/services/aaiService/responseInterfaces/getServicesResponseInterface.ts9
-rw-r--r--vid-webpack-master/src/app/services/aaiService/responseInterfaces/getSubDetailsResponseInterface.ts12
-rw-r--r--vid-webpack-master/src/app/services/aaiService/responseInterfaces/getSubscribersResponseInterface.ts5
-rw-r--r--vid-webpack-master/src/app/services/configuration.service.ts34
-rw-r--r--vid-webpack-master/src/app/services/data.service.ts528
-rw-r--r--vid-webpack-master/src/app/services/flags.resolve.ts14
-rw-r--r--vid-webpack-master/src/app/services/msoService/mso.service.ts26
-rw-r--r--vid-webpack-master/src/app/services/sdc.service.ts28
-rw-r--r--vid-webpack-master/src/app/services/service-planning.service.spec.ts467
-rw-r--r--vid-webpack-master/src/app/services/service-planning.service.ts282
-rw-r--r--vid-webpack-master/src/app/shared/api.service.ts6
-rw-r--r--vid-webpack-master/src/app/shared/components/ellipsis/ellipsis.component.ts27
-rw-r--r--vid-webpack-master/src/app/shared/components/error/error.component.service.ts35
-rw-r--r--vid-webpack-master/src/app/shared/components/formControlError/formControlError.component.html4
-rw-r--r--vid-webpack-master/src/app/shared/components/formControlError/formControlError.component.scss14
-rw-r--r--vid-webpack-master/src/app/shared/components/formControlError/formControlError.component.ts10
-rw-r--r--vid-webpack-master/src/app/shared/components/formGeneralErrors/formGeneralErrors.component.html10
-rw-r--r--vid-webpack-master/src/app/shared/components/formGeneralErrors/formGeneralErrors.component.scss48
-rw-r--r--vid-webpack-master/src/app/shared/components/formGeneralErrors/formGeneralErrors.component.ts11
-rw-r--r--vid-webpack-master/src/app/shared/components/messageBox/messageBox.component.ts50
-rw-r--r--vid-webpack-master/src/app/shared/components/messageBox/messageBox.data.ts51
-rw-r--r--vid-webpack-master/src/app/shared/components/messageBox/messageBox.service.spec.ts49
-rw-r--r--vid-webpack-master/src/app/shared/components/messageBox/messageBox.service.ts18
-rw-r--r--vid-webpack-master/src/app/shared/components/model-information/model-information.component.ts42
-rw-r--r--vid-webpack-master/src/app/shared/components/model-information/model-information.html12
-rw-r--r--vid-webpack-master/src/app/shared/components/model-information/model-information.scss34
-rw-r--r--vid-webpack-master/src/app/shared/components/no-content-message-and-icon/no-content-message-and-icon.component.html5
-rw-r--r--vid-webpack-master/src/app/shared/components/no-content-message-and-icon/no-content-message-and-icon.component.scss26
-rw-r--r--vid-webpack-master/src/app/shared/components/no-content-message-and-icon/no-content-message-and-icon.component.ts23
-rw-r--r--vid-webpack-master/src/app/shared/components/popover/popover.component.html8
-rw-r--r--vid-webpack-master/src/app/shared/components/popover/popover.component.scss4
-rw-r--r--vid-webpack-master/src/app/shared/components/popover/popover.component.ts17
-rw-r--r--vid-webpack-master/src/app/shared/components/spinner/spinner.component.html2
-rw-r--r--vid-webpack-master/src/app/shared/components/spinner/spinner.component.scss87
-rw-r--r--vid-webpack-master/src/app/shared/components/spinner/spinner.component.spec.ts42
-rw-r--r--vid-webpack-master/src/app/shared/components/spinner/spinner.component.ts18
-rw-r--r--vid-webpack-master/src/app/shared/components/validators/numbersLettersUnderscore/numbersLettersUnderscore.validator.spec.ts39
-rw-r--r--vid-webpack-master/src/app/shared/components/validators/numbersLettersUnderscore/numbersLettersUnderscore.validator.ts20
-rw-r--r--vid-webpack-master/src/app/shared/directives/inputPrevention/inputPreventionPattern.directive.spec.ts66
-rw-r--r--vid-webpack-master/src/app/shared/directives/inputPrevention/inputPreventionPattern.directive.ts24
-rw-r--r--vid-webpack-master/src/app/shared/directives/svg/svg.directive.html0
-rw-r--r--vid-webpack-master/src/app/shared/directives/svg/svg.directive.ts34
-rw-r--r--vid-webpack-master/src/app/shared/index.ts1
-rw-r--r--vid-webpack-master/src/app/shared/models/ServiceNodeTypes.ts8
-rw-r--r--vid-webpack-master/src/app/shared/models/aicZone.ts9
-rw-r--r--vid-webpack-master/src/app/shared/models/categoryParams.ts15
-rw-r--r--vid-webpack-master/src/app/shared/models/dynamicInput.ts123
-rw-r--r--vid-webpack-master/src/app/shared/models/externalComponentStatus.ts11
-rw-r--r--vid-webpack-master/src/app/shared/models/inputTypes.ts12
-rw-r--r--vid-webpack-master/src/app/shared/models/lcpRegion.ts11
-rw-r--r--vid-webpack-master/src/app/shared/models/lcpRegionTenants.ts13
-rw-r--r--vid-webpack-master/src/app/shared/models/lcpRegionsAndTenants.ts12
-rw-r--r--vid-webpack-master/src/app/shared/models/modelInfo.ts21
-rw-r--r--vid-webpack-master/src/app/shared/models/nodeModel.ts29
-rw-r--r--vid-webpack-master/src/app/shared/models/owningEntity.ts14
-rw-r--r--vid-webpack-master/src/app/shared/models/productFamily.ts13
-rw-r--r--vid-webpack-master/src/app/shared/models/project.ts14
-rw-r--r--vid-webpack-master/src/app/shared/models/selectOption.ts17
-rw-r--r--vid-webpack-master/src/app/shared/models/serviceInstance.ts28
-rw-r--r--vid-webpack-master/src/app/shared/models/serviceModel.ts44
-rw-r--r--vid-webpack-master/src/app/shared/models/serviceNodeTypeToModelKeyMapper.ts8
-rw-r--r--vid-webpack-master/src/app/shared/models/serviceType.ts17
-rw-r--r--vid-webpack-master/src/app/shared/models/subscriber.ts11
-rw-r--r--vid-webpack-master/src/app/shared/models/tenant.ts11
-rw-r--r--vid-webpack-master/src/app/shared/models/vfModule.ts39
-rw-r--r--vid-webpack-master/src/app/shared/models/vfModuleInstance.ts5
-rw-r--r--vid-webpack-master/src/app/shared/models/vfModuleTreeNode.ts17
-rw-r--r--vid-webpack-master/src/app/shared/models/vfModulesMap.ts5
-rw-r--r--vid-webpack-master/src/app/shared/models/vfcInstanceGroup.ts14
-rw-r--r--vid-webpack-master/src/app/shared/models/vfcInstanceGroupMap.ts5
-rw-r--r--vid-webpack-master/src/app/shared/models/vfcInstanceGroupProperties.ts7
-rw-r--r--vid-webpack-master/src/app/shared/models/vnfInstance.ts19
-rw-r--r--vid-webpack-master/src/app/shared/models/vnfModel.ts52
-rw-r--r--vid-webpack-master/src/app/shared/models/vnfTreeNode.ts18
-rw-r--r--vid-webpack-master/src/app/shared/pipes/capitalize/capitalize-and-format.pipe.spec.ts25
-rw-r--r--vid-webpack-master/src/app/shared/pipes/capitalize/capitalize-and-format.pipe.ts12
-rw-r--r--vid-webpack-master/src/app/shared/pipes/data-filter.pipe.ts29
-rw-r--r--vid-webpack-master/src/app/shared/pipes/dynamicInputLabel/dynamic-input-label.pipe.spec.ts43
-rw-r--r--vid-webpack-master/src/app/shared/pipes/dynamicInputLabel/dynamic-input-label.pipe.ts12
-rw-r--r--vid-webpack-master/src/app/shared/pipes/highlight-filter.pipe.ts10
-rw-r--r--vid-webpack-master/src/app/shared/pipes/serviceInfo/serviceInfo.pipe.spec.ts58
-rw-r--r--vid-webpack-master/src/app/shared/pipes/serviceInfo/serviceInfo.pipe.ts13
-rw-r--r--vid-webpack-master/src/app/shared/server/healthStatusService/health-status.service.spec.ts60
-rw-r--r--vid-webpack-master/src/app/shared/server/healthStatusService/health-status.service.ts17
-rw-r--r--vid-webpack-master/src/app/shared/server/serviceInfo/AuditStatus.model.ts10
-rw-r--r--vid-webpack-master/src/app/shared/server/serviceInfo/serviceInfo.model.ts38
-rw-r--r--vid-webpack-master/src/app/shared/server/serviceInfo/serviceInfo.service.spec.ts235
-rw-r--r--vid-webpack-master/src/app/shared/server/serviceInfo/serviceInfo.service.ts38
-rw-r--r--vid-webpack-master/src/app/shared/services/defaultDataServiceGenerator/default.data.generator.service.spec.ts73
-rw-r--r--vid-webpack-master/src/app/shared/services/defaultDataServiceGenerator/default.data.generator.service.ts82
-rw-r--r--vid-webpack-master/src/app/shared/shared.module.ts92
-rw-r--r--vid-webpack-master/src/app/shared/utils/constants.ts287
-rw-r--r--vid-webpack-master/src/app/shared/utils/httpInterceptor/httpInterceptor.service.ts32
-rw-r--r--vid-webpack-master/src/app/shared/utils/iframe.service.ts19
-rw-r--r--vid-webpack-master/src/app/shared/utils/log/log.service.spec.ts29
-rw-r--r--vid-webpack-master/src/app/shared/utils/log/log.service.ts58
-rw-r--r--vid-webpack-master/src/app/store/epics.ts13
-rw-r--r--vid-webpack-master/src/app/store/module.ts29
-rw-r--r--vid-webpack-master/src/app/store/reducers.ts17
-rw-r--r--vid-webpack-master/src/app/utils/utils.ts271
-rw-r--r--vid-webpack-master/src/app/vlanTagging/network-selector/network-selector.component.html14
-rw-r--r--vid-webpack-master/src/app/vlanTagging/network-selector/network-selector.component.scss17
-rw-r--r--vid-webpack-master/src/app/vlanTagging/network-selector/network-selector.component.ts66
-rw-r--r--vid-webpack-master/src/app/vlanTagging/vlan-tagging.component.html27
-rw-r--r--vid-webpack-master/src/app/vlanTagging/vlan-tagging.component.scss168
-rw-r--r--vid-webpack-master/src/app/vlanTagging/vlan-tagging.component.ts203
-rw-r--r--vid-webpack-master/src/app/vlanTagging/vlan-tagging.module.ts33
202 files changed, 14582 insertions, 0 deletions
diff --git a/vid-webpack-master/src/app/app.component.e2e-spec.js b/vid-webpack-master/src/app/app.component.e2e-spec.js
new file mode 100644
index 000000000..9ec9d23db
--- /dev/null
+++ b/vid-webpack-master/src/app/app.component.e2e-spec.js
@@ -0,0 +1,27 @@
+describe('App', function () {
+
+ beforeEach(function () {
+ browser.get('/');
+ });
+
+ it('should have a title', function () {
+ expect(browser.getTitle()).toEqual("Angular 2 App | ng2-webpack");
+ });
+
+ it('should have <header>', function () {
+ expect(element(by.css('my-app header')).isPresent()).toEqual(true);
+ });
+
+ it('should have <main>', function () {
+ expect(element(by.css('my-app main')).isPresent()).toEqual(true);
+ });
+
+ it('should have a main title', function () {
+ expect(element(by.css('main h1')).getText()).toEqual('Hello from Angular 2!');
+ });
+
+ it('should have <footer>', function () {
+ expect(element(by.css('my-app footer')).getText()).toEqual("Webpack Angular 2 Starter");
+ });
+
+});
diff --git a/vid-webpack-master/src/app/app.component.html b/vid-webpack-master/src/app/app.component.html
new file mode 100644
index 000000000..3768d0c53
--- /dev/null
+++ b/vid-webpack-master/src/app/app.component.html
@@ -0,0 +1,6 @@
+<main>
+ <router-outlet>
+ <message-box></message-box>
+ <spinner-component></spinner-component>
+ </router-outlet>
+</main>
diff --git a/vid-webpack-master/src/app/app.component.scss b/vid-webpack-master/src/app/app.component.scss
new file mode 100644
index 000000000..9149aefc0
--- /dev/null
+++ b/vid-webpack-master/src/app/app.component.scss
@@ -0,0 +1,24 @@
+// styles applied on :host are applied on the current component, "app" in this case
+:host {
+ display: block;
+}
+
+header {
+ background-color: #fff;
+ padding: 16px;
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ box-shadow: 2px 2px 6px rgba(0, 0, 0, 0.5);
+}
+
+main {
+ font-family: Arial, Helvetica, sans-serif;
+ display: block;
+}
+
+footer {
+ text-align: center;
+ font-size: 0.8em;
+}
diff --git a/vid-webpack-master/src/app/app.component.ts b/vid-webpack-master/src/app/app.component.ts
new file mode 100644
index 000000000..528c7d7a4
--- /dev/null
+++ b/vid-webpack-master/src/app/app.component.ts
@@ -0,0 +1,28 @@
+import {Component, Inject} from '@angular/core';
+
+import { ApiService } from './shared';
+
+import '../style/app.scss';
+import {NgRedux} from "@angular-redux/store";
+import {AppState} from "./store/reducers";
+import { LogService } from './shared/utils/log/log.service';
+
+@Component({
+ selector: 'vid-app', // <vid-app></vid-app>
+ templateUrl: './app.component.html',
+ styleUrls: ['./app.component.scss'],
+})
+export class AppComponent {
+ url = 'https://github.com/preboot/angular2-webpack';
+ title: string;
+
+
+ constructor(private api: ApiService, private store: NgRedux<AppState>, private _logService : LogService) {
+ this.title = this.api.title;
+ store.subscribe(()=>{
+ sessionStorage.setItem('reduxState', JSON.stringify(store.getState()));
+ });
+
+ this._logService.info("testing new log service");
+ }
+}
diff --git a/vid-webpack-master/src/app/app.module.ts b/vid-webpack-master/src/app/app.module.ts
new file mode 100644
index 000000000..a87ffb5b7
--- /dev/null
+++ b/vid-webpack-master/src/app/app.module.ts
@@ -0,0 +1,79 @@
+import { ApplicationRef, NgModule } from '@angular/core';
+import { BrowserModule } from '@angular/platform-browser';
+import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { AppComponent } from './app.component';
+import { HomeComponent } from './home/home.component';
+import { ApiService } from './shared';
+import { routing } from './app.routing';
+import { createNewHosts, removeNgStyles } from '@angularclass/hmr';
+import { BrowseSdcModule } from './browseSdc/browseSdc.module';
+import { VlanTaggingModule } from './vlanTagging/vlan-tagging.module'
+import { BootstrapModalModule } from 'ng2-bootstrap-modal';
+import { HashLocationStrategy, LocationStrategy } from "@angular/common";
+import { InstantiationStatusModule } from './instantiationStatus/InstantiationStatus.module';
+import { SharedModule } from './shared/shared.module';
+import { AngularSvgIconModule } from 'angular-svg-icon';
+import { NgReduxModule } from '@angular-redux/store';
+import { StoreModule } from "./store/module";
+import { HttpInterceptorService } from './shared/utils/httpInterceptor/httpInterceptor.service';
+import { DrawingBoardModule } from './drawingBoard/drawingBoard.module';
+import { HealthStatusComponent } from './healthStatus/health-status.component';
+import { ScrollToModule } from '@nicky-lenaers/ngx-scroll-to';
+import { LogService } from './shared/utils/log/log.service';
+
+@NgModule({
+ imports: [
+ BrowserModule,
+ HttpClientModule,
+ FormsModule,
+ routing,
+ SharedModule.forRoot(),
+ ScrollToModule.forRoot(),
+ DrawingBoardModule,
+ VlanTaggingModule,
+ InstantiationStatusModule,
+ BrowseSdcModule,
+ BootstrapModalModule,
+ BrowseSdcModule,
+ AngularSvgIconModule,
+ ReactiveFormsModule,
+ NgReduxModule,
+ StoreModule,
+ ],
+ declarations: [
+ AppComponent,
+ HomeComponent,
+ HealthStatusComponent
+ ],
+ providers: [
+ ApiService,
+ LogService,
+ { provide: LocationStrategy, useClass: HashLocationStrategy },
+ { provide: HTTP_INTERCEPTORS, useClass: HttpInterceptorService, multi: true }
+ ],
+ bootstrap: [AppComponent]
+})
+export class AppModule {
+ private static CustomLoader: any;
+
+ constructor(public appRef: ApplicationRef) {
+ //for ng2-bootstrap-modal in angualar 5
+ Object.defineProperty(appRef, '_rootComponents', { get: () => appRef['components'] });
+ }
+ hmrOnInit(store) {
+ console.log('HMR store', store);
+ }
+ hmrOnDestroy(store) {
+ let cmpLocation = this.appRef.components.map(cmp => cmp.location.nativeElement);
+ // recreate elements
+ store.disposeOldHosts = createNewHosts(cmpLocation);
+ // remove styles
+ removeNgStyles();
+ }
+ hmrAfterDestroy(store) {
+ // display new elements
+ store.disposeOldHosts();
+ delete store.disposeOldHosts;
+ }
+}
diff --git a/vid-webpack-master/src/app/app.routing.ts b/vid-webpack-master/src/app/app.routing.ts
new file mode 100644
index 000000000..e6f42f9ed
--- /dev/null
+++ b/vid-webpack-master/src/app/app.routing.ts
@@ -0,0 +1,40 @@
+import {RouterModule, Routes} from '@angular/router';
+
+import {HomeComponent} from './home/home.component';
+import {BrowseSdcComponent} from './browseSdc/browseSdc.component';
+import {ServicePlanningComponent, ServicePlanningEmptyComponent} from './drawingBoard/service-planning/service-planning.component';
+import {VlanTaggingComponent} from './vlanTagging/vlan-tagging.component';
+import {ServicePopupComponent} from './components/service-popup/service-popup.component';
+import { InstantiationStatusComponent } from './instantiationStatus/instantiationStatus.component';
+import {HealthStatusComponent} from "./healthStatus/health-status.component";
+import {FlagsResolve} from "./services/flags.resolve";
+
+const routes: Routes = [
+ { path: '', component: HomeComponent, pathMatch: 'full' ,resolve : {
+ flags : FlagsResolve,
+ }},
+ { path: 'browseSdc', component: BrowseSdcComponent, resolve : {
+ flags : FlagsResolve,
+ }},
+ { path: 'servicePlanning', component: ServicePlanningComponent, resolve : {
+ flags : FlagsResolve,
+ }},
+ { path: 'servicePlanningEmpty', component: ServicePlanningEmptyComponent, resolve : {
+ flags : FlagsResolve,
+ }},
+ { path: 'servicePopup', component: ServicePopupComponent, resolve : {
+ flags : FlagsResolve,
+ }},
+ { path :'vlan', component : VlanTaggingComponent, resolve : {
+ flags : FlagsResolve,
+ }},
+ { path: 'instantiationStatus', component: InstantiationStatusComponent, resolve : {
+ flags : FlagsResolve,
+ }},
+ { path: 'healthStatus', component: HealthStatusComponent, resolve : {
+ flags : FlagsResolve,
+ }}
+
+];
+
+export const routing = RouterModule.forRoot(routes);
diff --git a/vid-webpack-master/src/app/browseSdc/browseSdc.component.html b/vid-webpack-master/src/app/browseSdc/browseSdc.component.html
new file mode 100644
index 000000000..7ffd7931c
--- /dev/null
+++ b/vid-webpack-master/src/app/browseSdc/browseSdc.component.html
@@ -0,0 +1,26 @@
+<div>
+
+ <span class="statusLine" [hidden]="!isSpinnerVisible">
+ <img src="./img/spinner.gif"/>
+ </span>
+ <span class="statusLine" [hidden]="!isProgressVisible">
+ <label>Status:</label><span class="status"><span [hidden]="!error"><font color='red'><b>Error: </b></font></span>{{status}}</span>
+ </span>
+ <br><br>
+ <div>
+ <input class="form-control search-query" placeholder="Filter..." data-tests-id="browseFilter" type="text" [(ngModel)]="filterQuery" size="20" style="width: 250px;">
+ </div>
+
+ <h1 class="heading1" style="margin-top:20px;">Browse SDC Service Models</h1>
+ <div style="margin-top:30px">
+ <button (click)="deploy()">deploy</button>
+ <vid-table
+ [options]="tableOptions"
+ [filterQuery]="filterQuery"
+ (clickEvent)="clickAction($event)">
+ Loading table...
+ </vid-table>
+ </div>
+</div>
+
+
diff --git a/vid-webpack-master/src/app/browseSdc/browseSdc.component.scss b/vid-webpack-master/src/app/browseSdc/browseSdc.component.scss
new file mode 100644
index 000000000..0d1678a94
--- /dev/null
+++ b/vid-webpack-master/src/app/browseSdc/browseSdc.component.scss
@@ -0,0 +1,59 @@
+div[ng-controller=ServiceModelController] .popupContents {
+ text-align: left;
+}
+
+div[ng-controller=ServiceModelController] .statusLine {
+ vertical-align: center;
+}
+
+div[ng-controller=ServiceModelController] .statusLine img {
+ width: 20px;
+ margin: 10px;
+}
+
+div[ng-controller=ServiceModelController] .status {
+ margin-left: 5px;
+}
+
+div[ng-controller=ServiceModelController] .feedback {
+ height: 35px;
+ vertical-align: center;
+}
+
+div[ng-controller=ServiceModelController] .progress {
+ margin: 0px 10px;
+ font-weight: bold;
+}
+
+div[ng-controller=ServiceModelController] .error {
+ width: 630px;
+ font-weight: bold;
+ font-size: 16px;
+ color: red;
+ margin: 0px 10px 0px 45px;
+}
+
+div[ng-controller=ServiceModelController] .error img {
+ width: 25px;
+ margin: 0px 10px;
+}
+
+div[ng-controller=ServiceModelController] .buttonRow {
+ text-align: center;
+ margin-bottom: 10px;
+}
+
+div[ng-controller=ServiceModelController] .log {
+ width: 700px;
+ height: 500px;
+ border: solid black 1px;
+ text-align: left !important;
+ margin: 10px;
+ padding: 10px;
+ overflow: auto;
+}
+
+
+.previous-versions-button {
+ width: 113px;
+}
diff --git a/vid-webpack-master/src/app/browseSdc/browseSdc.component.ts b/vid-webpack-master/src/app/browseSdc/browseSdc.component.ts
new file mode 100644
index 000000000..46f37dc2e
--- /dev/null
+++ b/vid-webpack-master/src/app/browseSdc/browseSdc.component.ts
@@ -0,0 +1,176 @@
+import {Component, Input, OnInit} from '@angular/core';
+import * as _ from 'lodash';
+import {SdcService} from '../services/sdc.service';
+import {DialogService} from 'ng2-bootstrap-modal';
+import {Constants} from '../shared/utils/constants';
+import {CustomTableColumnDefinition, CustomTableOptions} from './vid-table/vid-table.component';
+import {ServicePopupComponent} from "../components/service-popup/service-popup.component";
+import { PreviousVersionsComponent } from './previous-versions/previous-versions.component';
+
+@Component({
+ selector: 'browse-sdc',
+ templateUrl: './browseSdc.component.html',
+ styleUrls: ['./browseSdc.component.scss']
+})
+
+
+export class BrowseSdcComponent implements OnInit {
+
+ isSpinnerVisible = false;
+ isProgressVisible = false;
+ error: boolean;
+ status: string;
+ // table
+
+ private basicColumns: CustomTableColumnDefinition[];
+ @Input () filterQuery = '';
+ tableOptions: CustomTableOptions;
+ private wholeData: any[];
+
+ constructor(private _sdcService: SdcService, private dialogService: DialogService) {}
+
+ initTableOptions() {
+ this.basicColumns = [
+ { displayName: 'Action', key: 'action', type: 'button' , text: 'deploy', action: 'deploy' },
+ { displayName: 'UUID', key: 'uuid', filter: 'text'},
+ { displayName: 'invariantUUID', key: 'invariantUUID', filter: 'text'},
+ { displayName: 'Name', key: 'name', filter: 'text'},
+ { displayName: 'Version', key: 'version', filter: 'text'},
+ { displayName: 'Category', key: 'category', filter: 'text'},
+ { displayName: 'Distribution Status', key: 'distributionStatus', filter: 'text'},
+ { displayName: 'Last Updated By', key: 'lastUpdaterUserId', filter: 'text'},
+ { displayName: 'Tosca Model', key: 'toscaModelUrl', filter: 'text'}
+ ];
+
+ let columns: CustomTableColumnDefinition[] = this.basicColumns.concat(
+ {displayName: 'Action', key: 'actions', type: 'button', text: 'Previous Versions',
+ showCondition: 'hasPreviousVersion', action: 'loadPreviousData' }
+ );
+
+ this.tableOptions = {
+ data: [],
+ columns: columns,
+ config: {
+ sortBy: 'name',
+ sortOrder: 'asc',
+ pageSize: 10,
+ pageNumber: 1,
+ totalCount: 0,
+ totalPages: 0,
+ maxSize: 10,
+ showSelectCheckbox: true,
+ showSelectAll: true,
+ showSort: true,
+ clientSort: true,
+ clientPaging: true,
+ // displayPager: true,
+ // displayPageSize: true,
+ stickyHeader: true,
+ stickyHeaderOffset: 0,
+ stickyContainer: '.table1-container'
+ },
+ };
+ }
+ private deploy(service: any): void {
+ if (service) {
+ console.log('this row uuid:' + service.uuid);
+ }
+
+ this.dialogService.addDialog(ServicePopupComponent, {
+ })
+ }
+
+ private filterDataWithHigherVersion(serviceData) {
+ let delimiter = '$$';
+ let filterDataServices = {};
+ for (let i = 0; i < serviceData.length; i++) {
+ let index = serviceData[i].invariantUUID.trim() + delimiter + serviceData[i].name.trim();
+ if (!filterDataServices[index]) {
+ filterDataServices[index] = {
+ service: serviceData[i],
+ hasPreviousVersion: false
+ };
+ } else {
+ filterDataServices[index].hasPreviousVersion = true;
+ if (parseFloat(serviceData[i].version.trim()) > parseFloat(filterDataServices[index].service.version.trim())) {
+ filterDataServices[index].service = serviceData[i];
+ }
+ }
+ }
+ return Object.keys(filterDataServices).map(function (key) {
+ let service = filterDataServices[key].service;
+ service.hasPreviousVersion = filterDataServices[key].hasPreviousVersion;
+ return service;
+ });
+ }
+
+ private initData() {
+ this.isProgressVisible = true;
+ this.isSpinnerVisible = true;
+ console.log('getServicesModels: ');
+ this._sdcService.getServicesModels().subscribe(
+ // onNext() function
+ value => this.getServiceCallback(value),
+ // onError() function
+ error => this.getServiceOnError(error),
+ // onComplete() function
+ () => console.log('completed')
+ );
+ }
+
+ private getServiceCallback(responseBody: any): void {
+ console.log('response is ' , responseBody);
+ this.wholeData = responseBody.services;
+ this.tableOptions.data = this.filterDataWithHigherVersion(responseBody.services);
+ this.isSpinnerVisible = false;
+ this.isProgressVisible = false;
+ }
+ private getServiceOnError(error: any): void {
+ console.log('error is ' , error);
+ this.status = Constants.Status.FAILED_SERVICE_MODELS_ASDC;
+ this.error = true;
+ this.isSpinnerVisible = false;
+ }
+
+ private loadPreviousVersionData(service): void {
+ let previousVersionData: any[] = _.filter(this.wholeData, function(item) {
+ return item.invariantUUID === service.invariantUUID && item.name === service.name && service.version !== item.version;
+ });
+
+ let modalTableOptions: CustomTableOptions = {
+ data: previousVersionData,
+ columns: this.basicColumns,
+ config: {
+ sortBy: 'version',
+ sortOrder: 'desc'}
+ };
+ // open modal
+ this.dialogService.addDialog(PreviousVersionsComponent, {
+ title: service.name + ' - Previous Version',
+ tableOptions: modalTableOptions
+ })
+ .subscribe( service => {
+ if (service) {
+ this.deploy(service);
+ }
+ });
+ }
+
+
+ public clickAction(row) {
+ switch (row.actionName) {
+ case 'loadPreviousData':
+ this.loadPreviousVersionData(row);
+ break;
+ case 'deploy':
+ this.deploy(row);
+ break;
+ }
+ }
+
+ ngOnInit() {
+ console.log('Browse SDC Service Models');
+ this.initTableOptions();
+ this.initData();
+ }
+}
diff --git a/vid-webpack-master/src/app/browseSdc/browseSdc.module.ts b/vid-webpack-master/src/app/browseSdc/browseSdc.module.ts
new file mode 100644
index 000000000..b7dd78e54
--- /dev/null
+++ b/vid-webpack-master/src/app/browseSdc/browseSdc.module.ts
@@ -0,0 +1,35 @@
+
+import { NgModule } from '@angular/core';
+import {BrowseSdcComponent} from './browseSdc.component';
+import {VidTableComponent} from './vid-table/vid-table.component';
+import {SdcService} from '../services/sdc.service';
+import {CommonModule} from '@angular/common';
+import {FormsModule, ReactiveFormsModule} from '@angular/forms';
+import {DataTableModule} from 'angular2-datatable';
+import {BootstrapModalModule} from 'ng2-bootstrap-modal';
+import {PreviousVersionsComponent} from './previous-versions/previous-versions.component';
+import {ServicePopupComponent} from '../components/service-popup/service-popup.component';
+import {ServiceInstanceDetailsComponent} from "../components/service-popup/service-instance-details/service-instance-details.component";
+import {TooltipModule} from 'ngx-tooltip';
+import {InputsModule} from "../modules/inputs.module";
+import {VnfPopupComponent} from "../components/vnf-popup/vnf-popup.components";
+import {VnfInstanceDetailsComponent} from "../components/vnf-popup/vnf-instance-details/vnf-instance-details.component";
+import { VnfInstanceDetailsService } from '../components/vnf-popup/vnf-instance-details/vnf-instance-details.service';
+import { SharedModule } from '../shared/shared.module';
+import { ServiceInstanceDetailsService } from '../components/service-popup/service-instance-details/service-instance-details.service';
+import { ServicePopupService } from '../components/service-popup/service-popup.service';
+import { DataFilterPipe } from '../shared/pipes/data-filter.pipe';
+
+
+@NgModule({
+ imports: [CommonModule, FormsModule, ReactiveFormsModule, BootstrapModalModule, DataTableModule, TooltipModule, InputsModule, SharedModule.forRoot()],
+ providers: [SdcService, VnfInstanceDetailsService, ServiceInstanceDetailsService, ServicePopupService],
+ declarations: [BrowseSdcComponent, VidTableComponent, DataFilterPipe, PreviousVersionsComponent,
+ ServicePopupComponent, ServiceInstanceDetailsComponent, VnfPopupComponent, VnfInstanceDetailsComponent
+ ],
+ entryComponents: [BrowseSdcComponent, PreviousVersionsComponent, ServicePopupComponent, VnfPopupComponent],
+ exports: [ ]
+
+})
+
+export class BrowseSdcModule { }
diff --git a/vid-webpack-master/src/app/browseSdc/previous-versions/previous-versions.component.ts b/vid-webpack-master/src/app/browseSdc/previous-versions/previous-versions.component.ts
new file mode 100644
index 000000000..8faf04d6c
--- /dev/null
+++ b/vid-webpack-master/src/app/browseSdc/previous-versions/previous-versions.component.ts
@@ -0,0 +1,29 @@
+import { Component } from '@angular/core';
+import { DialogComponent, DialogService } from 'ng2-bootstrap-modal';
+import { CustomTableOptions } from '../vid-table/vid-table.component';
+
+export interface PreviousVersionsModel {
+
+ title: string;
+ tableOptions: CustomTableOptions;
+}
+
+@Component({
+ selector: 'previous-versions',
+ templateUrl: 'previous-versions.html',
+ styleUrls: ['previous-versions.css']
+})
+export class PreviousVersionsComponent extends DialogComponent<PreviousVersionsModel, boolean> implements PreviousVersionsModel {
+
+ title: string;
+ tableOptions: CustomTableOptions;
+
+ constructor(dialogService: DialogService) {
+ super(dialogService);
+ }
+
+ public deploy(row) {
+ this.result = row;
+ this.close();
+ }
+}
diff --git a/vid-webpack-master/src/app/browseSdc/previous-versions/previous-versions.css b/vid-webpack-master/src/app/browseSdc/previous-versions/previous-versions.css
new file mode 100644
index 000000000..92bcbd100
--- /dev/null
+++ b/vid-webpack-master/src/app/browseSdc/previous-versions/previous-versions.css
@@ -0,0 +1,4 @@
+.modal-dialog {
+ width: 1145px;
+ font-size: 11px;
+}
diff --git a/vid-webpack-master/src/app/browseSdc/previous-versions/previous-versions.html b/vid-webpack-master/src/app/browseSdc/previous-versions/previous-versions.html
new file mode 100644
index 000000000..68209b8e8
--- /dev/null
+++ b/vid-webpack-master/src/app/browseSdc/previous-versions/previous-versions.html
@@ -0,0 +1,18 @@
+<div class="modal-dialog">
+ <div class="modal-content">
+ <div class="modal-header">
+ <button type="button" class="close" (click)="close()" >&times;</button>
+ <h4 class="modal-title">{{title}}</h4>
+ </div>
+ <div class="modal-body">
+ <vid-table
+ [options]="tableOptions"
+ (clickEvent)="deploy($event)">
+ Loading table...
+ </vid-table>
+ </div>
+ <div class="modal-footer">
+ <button type="button" class="btn btn-default" (click)="close()" >Cancel</button>
+ </div>
+ </div>
+</div>
diff --git a/vid-webpack-master/src/app/browseSdc/vid-table/vid-table.component.html b/vid-webpack-master/src/app/browseSdc/vid-table/vid-table.component.html
new file mode 100644
index 000000000..5650e5d35
--- /dev/null
+++ b/vid-webpack-master/src/app/browseSdc/vid-table/vid-table.component.html
@@ -0,0 +1,26 @@
+<table class="table table-hover table-striped table-sortable" [mfData]="options.data | dataFilter : filterQuery" #mf="mfDataTable" [(mfSortBy)]="options.config.sortBy" [(mfSortOrder)]="options.config.sortOrder" [mfRowsOnPage]="10">
+ <thead>
+ <tr>
+ <th *ngFor="let column of options.columns">
+ <mfDefaultSorter by="{{column.key}}"> {{column.displayName}}</mfDefaultSorter>
+ </th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr *ngFor="let row of mf.data">
+ <td *ngFor="let column of options.columns" >
+ <button class="btn btn-primary" *ngIf="column.type==='button' && (!column.showCondition || row[column.showCondition])" title="{{column.text}}" (click)="clickBtn(row, column.action)">
+ {{column.text}}
+ </button>
+ {{row[column.key]}}
+ </td>
+ </tr>
+ </tbody>
+ <tfoot>
+ <tr>
+ <td colspan="5">
+ <mfBootstrapPaginator [rowsOnPageSet]="[10,15,20]"></mfBootstrapPaginator>
+ </td>
+ </tr>
+ </tfoot>
+</table>
diff --git a/vid-webpack-master/src/app/browseSdc/vid-table/vid-table.component.scss b/vid-webpack-master/src/app/browseSdc/vid-table/vid-table.component.scss
new file mode 100644
index 000000000..f34887987
--- /dev/null
+++ b/vid-webpack-master/src/app/browseSdc/vid-table/vid-table.component.scss
@@ -0,0 +1,40 @@
+table > thead > tr > th {
+ cursor: pointer;
+ position: relative;
+ background-image: none;
+ color: #fff;
+ background-color: #666;
+ a{
+ color: #fff;
+ }
+}
+
+.table-sortable > thead > tr > th:after,
+.table-sortable > thead > tr > th.sort-false:after,
+.table-sortable > thead > tr > th.sort-true:after {
+ font-family: FontAwesome;
+ padding-left: 5px;
+}
+
+.table-sortable > thead > tr > th:after {
+ content: "\f0dc";
+ color: #ddd;
+}
+.table-sortable > thead > tr > th.sort-false:after {
+ content: "\f0de";
+ color: #767676;
+}
+.table-sortable > thead > tr > th.sort-true:after {
+ content: "\f0dd";
+ color: #767676;
+}
+//.table-sortable > tbody > td >
+.table-sortable {
+ tbody{
+ td{
+ .btn-primary{
+ min-width: 100px;
+ }
+ }
+ }
+}
diff --git a/vid-webpack-master/src/app/browseSdc/vid-table/vid-table.component.ts b/vid-webpack-master/src/app/browseSdc/vid-table/vid-table.component.ts
new file mode 100644
index 000000000..aa2030908
--- /dev/null
+++ b/vid-webpack-master/src/app/browseSdc/vid-table/vid-table.component.ts
@@ -0,0 +1,59 @@
+/**
+ * Created by cp2122 on 1/2/2018.
+ */
+import { Component, Input, EventEmitter, Output } from '@angular/core';
+export class CustomTableColumnDefinition {
+ public displayName = '';
+ public key = '';
+ public type? = 'text';
+ public text? = ''; // for button
+ public action? = ''; // for button - callback
+ public showCondition? = ''; // for button
+ // public binding = '';
+ public filter? = '';
+ // public computedClass: any;
+ // public isComputed = false;
+ // public isAnchor = false;
+ // public srefBinding = '';
+}
+
+export class CustomTableConfig {
+ public sortBy = '';
+ public sortOrder = 'desc';
+ public pageSize? = 10;
+ public pageNumber? = 1;
+ public totalCount? = 0;
+ public totalPages? = 0;
+ public maxSize? = 10;
+ public showSelectCheckbox? = false;
+ public showSelectAll? = true;
+ public showSort? = true;
+ public clientSort? = true;
+ public clientPaging? = true;
+ public stickyHeader? = true;
+ public stickyHeaderOffset? = 0;
+ public stickyContainer? = '';
+}
+
+export class CustomTableOptions {
+ public data: any[];
+ public columns: Array<CustomTableColumnDefinition>;
+ public config: CustomTableConfig;
+ // public callbacks: any;
+}
+@Component({
+ selector: 'vid-table',
+ styleUrls: ['./vid-table.component.scss'],
+ templateUrl: './vid-table.component.html'
+})
+
+export class VidTableComponent {
+ @Input() options: CustomTableOptions;
+ @Input() filterQuery = '';
+
+ @Output() clickEvent = new EventEmitter<any>();
+ clickBtn(row, actionName) {
+ row.actionName = actionName;
+ this.clickEvent.emit(row);
+ }
+}
diff --git a/vid-webpack-master/src/app/components/dynamic-inputs/dynamic-inputs.component.ts b/vid-webpack-master/src/app/components/dynamic-inputs/dynamic-inputs.component.ts
new file mode 100644
index 000000000..921c923df
--- /dev/null
+++ b/vid-webpack-master/src/app/components/dynamic-inputs/dynamic-inputs.component.ts
@@ -0,0 +1,80 @@
+import {Component, Input, OnInit} from '@angular/core';
+import {FormControl, FormGroup, Validators} from "@angular/forms";
+import {DynamicInput, DynamicMultiSelect, DynamicNumber, DynamicSelect} from "../../shared/models/dynamicInput";
+
+@Component({
+ selector: 'dynamic-inputs',
+ templateUrl: './dynamic-inputs.html',
+ styleUrls: ['./dynamic-inputs.scss']
+})
+
+export class DynamicInputsComponent implements OnInit{
+ @Input() public list:any[] = [];
+ @Input() public group: FormGroup;
+
+ private dynamicList:DynamicInput<any>[] = [];
+
+ isDynamicNumber(item: any): item is DynamicNumber {
+ return item;
+ }
+
+ buildValidators(item: DynamicInput<any>) {
+ let validatorArr = [];
+ item.maxLength && validatorArr.push(Validators.maxLength(item.maxLength));
+ item.minLength && validatorArr.push(Validators.minLength(item.minLength));
+ if(this.isDynamicNumber(item)) {
+ item.max && validatorArr.push(Validators.max(item.max));
+ item.min && validatorArr.push(Validators.min(item.min));
+ }
+ return Validators.compose(validatorArr);
+ }
+
+ ngOnInit(): void {
+ this.list.forEach((item)=> {
+ let dynamicItem: DynamicInput<any>;
+ switch (item.type) {
+ case 'multi_select':
+ item.optionList.forEach(function(option) { option.id = option.id||option.name;
+ option.itemName = option.name;});
+ item.settings = {
+ disabled: !item.isEnabled,
+ text: item.prompt,
+ };
+ dynamicItem = new DynamicMultiSelect(item);
+ break;
+ case 'select':
+ let defaultValue:any = item.optionList.find((option) => option.isDataLoading && option.name);
+ item.value = defaultValue && defaultValue.id;
+ dynamicItem = new DynamicSelect(item);
+ break;
+ case 'boolean':
+ item.value = item.value || false;
+ item.optionList = [{name: true, isPermitted: true, isDataLoading: item.value}, {name: false, isPermitted: true, isDataLoading: !item.value}];
+
+ dynamicItem = new DynamicSelect(item);
+ break;
+ case 'number':
+ dynamicItem = new DynamicNumber(item);
+ break;
+ case 'file':
+ dynamicItem = new DynamicInput<any>(item);
+ break;
+ case 'checkbox':
+ dynamicItem = new DynamicInput<boolean>(item);
+ break;
+ case 'map':
+ item.prompt = "{<key1>: <value1>,\.\.\.,<keyN>: <valueN>}";
+ dynamicItem = new DynamicInput<string>(item);
+ break;
+ case 'list':
+ item.prompt = "[<value1>,...,<valueN>]";
+ dynamicItem = new DynamicInput<string>(item);
+ break;
+ default: dynamicItem = new DynamicInput<string>(item);
+ }
+ this.dynamicList.push(dynamicItem);
+ this.group.addControl(dynamicItem.name, new FormControl({value: dynamicItem.value, disabled: !dynamicItem.isEnabled}, this.buildValidators(dynamicItem)));
+ })
+ }
+
+}
diff --git a/vid-webpack-master/src/app/components/dynamic-inputs/dynamic-inputs.html b/vid-webpack-master/src/app/components/dynamic-inputs/dynamic-inputs.html
new file mode 100644
index 000000000..a933364e2
--- /dev/null
+++ b/vid-webpack-master/src/app/components/dynamic-inputs/dynamic-inputs.html
@@ -0,0 +1,22 @@
+<div *ngFor="let item of dynamicList">
+ <div id="{{item.id}}" class="details-item" [ngSwitch]="item.type" [formGroup]="group" [hidden]="!item.isVisible">
+ <label>{{item.name | dynamicInputLabel }}</label>
+ <select *ngSwitchCase="item.type === 'select'|| item.type === 'boolean'? item.type: ''" name="{{item.name}}" class="form-control input-text" [formControlName]="item.name" title="{{item.description}}" [required]="item.isRequired && item.isVisible" maxlength="{{item.maxLength}}" minlength="{{item.minLength}}">
+ <option value="null" [selected]="item.value == null || item.value == undefined" hidden disabled>{{item.prompt}}</option>
+ <option *ngFor="let option of item.optionList" [ngValue]="option.id || option.name" [disabled]="!option.isPermitted" [selected]="option.isDataLoading">{{option.name}}</option>
+ </select>
+ <angular2-multiselect *ngSwitchCase="'multi_select'" [formControlName]="item.name" [(ngModel)]="item.selectedItems" [data]="item.optionList" [settings]="item.settings" title="{{item.description}}" [required]="item.isRequired && item.isVisible"></angular2-multiselect>
+ <input *ngSwitchCase="'number'" name="{{item.name}}" class="form-control input-text" [formControlName]="item.name" type="number" placeholder="{{item.prompt}}" title="{{item.description}}" min="{{item.min}}" max="{{item.max}}" [readonly]="item.isReadOnly" [required]="item.isRequired && item.isVisible">
+ <div *ngSwitchCase="'file'">
+
+ <label class="dynamicFileName" for="dynamicFileInput-{{item.name}}">
+ <input id="dynamicFileInput-{{item.name}}" name="{{item.name}}" class="form-control input-text" [formControlName]="item.name" type="file" placeholder="{{item.prompt}}" [readonly]="item.isReadOnly" [required]="item.isRequired && item.isVisible">
+ <label for="dynamicFileInput-{{item.name}}" class="labelForImage">
+ <span class="icon-browse"></span>
+ </label>
+ </label>
+ </div>
+ <input *ngSwitchCase="'checkbox'" name="{{item.name}}" [formControlName]="item.name" type="checkbox" data-toggle="toggle" title="{{item.description}}" [readonly]="item.isReadOnly" [required]="item.isRequired && item.isVisible">
+ <input *ngSwitchDefault name="{{item.name}}" class="form-control input-text" [formControlName]="item.name" placeholder="{{item.prompt}}" title="{{item.description}}" maxlength="{{item.maxLength}}" minlength="{{item.minLength}}" [readonly]="item.isReadOnly" [required]="item.isRequired && item.isVisible"/>
+ </div>
+</div>
diff --git a/vid-webpack-master/src/app/components/dynamic-inputs/dynamic-inputs.scss b/vid-webpack-master/src/app/components/dynamic-inputs/dynamic-inputs.scss
new file mode 100644
index 000000000..11a141420
--- /dev/null
+++ b/vid-webpack-master/src/app/components/dynamic-inputs/dynamic-inputs.scss
@@ -0,0 +1,58 @@
+input[type=file] {
+ opacity: 0;
+ position: relative;
+ z-index: 1;
+ width: 0.5px;
+ height: 0.5px;
+ display: inline-block;
+ input {
+ display: none;
+ }
+}
+
+.dynamicFileName {
+ width: 100%;
+ height: 34px;
+ background: #FFFFFF;
+ border: 1px solid #D2D2D2;
+ border-radius: 2px;
+ display: inline-block;
+ line-height: 34px;
+ font-weight: normal !important;
+ padding-left: 3px;
+ border-bottom-right-radius: 0;
+ border-top-right-radius: 0;
+}
+
+.labelForImage {
+ background: #F2F2F2;
+ border-left: 1px solid #D2D2D2;
+ float: right;
+ height: 32px;
+}
+
+.icon-browse:before {
+ content: "\e90d";
+ color: #5A5A5A;
+ font-size: 15px;
+ cursor: pointer;
+ width: 34px;
+ height: 100%;
+ line-height: 34px;
+ text-align: center;
+ display: inline-block;
+ vertical-align: super;
+ border-radius: 2px;
+ border-bottom-left-radius: 0;
+ border-top-left-radius: 0;
+}
+
+.icon-browse:hover::before {
+ background-color: #E6F6FB;
+ color: #009FDB;
+}
+
+.icon-browse:active::before {
+ background-color: #E6F6FB;
+ color: #009FDB;
+}
diff --git a/vid-webpack-master/src/app/components/form-async/form-async.component.ts b/vid-webpack-master/src/app/components/form-async/form-async.component.ts
new file mode 100644
index 000000000..e71c4446b
--- /dev/null
+++ b/vid-webpack-master/src/app/components/form-async/form-async.component.ts
@@ -0,0 +1,80 @@
+import {Component, Input, OnInit, ViewChild} from '@angular/core';
+import { NgRedux, select } from '@angular-redux/store';
+import { Observable } from "rxjs/Observable";
+import { updateProductFamilies } from "../../service.actions";
+import { AppState } from "../../store/reducers";
+import {
+ loadProductFamiliesAction, loadLcpTenant, loadAicZones,
+ loadCategoryParameters
+} from '../../services/aaiService/aai.actions';
+import { LcpRegionsAndTenants } from "../../shared/models/lcpRegionsAndTenants";
+import {NgForm} from "@angular/forms";
+import {SelectOption} from "../../shared/models/selectOption";
+import {VNFModel} from "../../shared/models/vnfModel";
+
+@Component({
+ selector: "formasync",
+ templateUrl: "form-async.template.html",
+ styleUrls: ["form-async.style.scss"],
+
+})
+
+export class formasync implements OnInit {
+
+ constructor(private store: NgRedux<AppState>) { }
+
+ @ViewChild('form') form: NgForm;
+
+ @Input()
+ set model(model: VNFModel) {
+ if (model) {
+ this.isUserProvidedNaming = model.isUserProvidedNaming;
+ }
+ };
+
+ @select(['service', 'productFamilies'])
+ readonly productFamilies: Observable<any>;
+
+ @select(['service', 'lcpRegionsAndTenants'])
+ readonly lcpRegionsAndTenants: Observable<any>;
+
+ @select(['service', 'lcpRegionsAndTenants', 'lcpRegionList'])
+ readonly lcpRegions: Observable<any>;
+
+ @select(['service', 'aicZones'])
+ readonly aicZones: Observable<any>;
+
+ @select(['service', 'categoryParameters', 'platformList'])
+ readonly platformList: Observable<any>;
+
+ @select(['service', 'categoryParameters', 'lineOfBusinessList'])
+ readonly lineOfBusinessList: Observable<any>;
+
+ rollbackOnFailure = [
+ new SelectOption({id: 'true', name: 'Rollback'}),
+ new SelectOption({id: 'false', name: 'Don\'t Rollback'})
+ ];
+ tenants = [];
+
+ serviceInstance: any = {
+ rollback:'true'
+ };
+
+ isUserProvidedNaming: boolean = false;
+
+ onLcpSelect(newValue: string) {
+ let value: LcpRegionsAndTenants = undefined;
+ this.lcpRegionsAndTenants.subscribe(data => value = data);
+ this.tenants = value.lcpRegionsTenantsMap[newValue];
+ }
+
+ ngOnInit() {
+ this.store.dispatch(loadProductFamiliesAction());
+ this.store.dispatch(loadLcpTenant());
+ this.store.dispatch(loadAicZones());
+ this.store.dispatch(loadCategoryParameters());
+ }
+}
+
+
+
diff --git a/vid-webpack-master/src/app/components/form-async/form-async.style.scss b/vid-webpack-master/src/app/components/form-async/form-async.style.scss
new file mode 100644
index 000000000..e6c89bcae
--- /dev/null
+++ b/vid-webpack-master/src/app/components/form-async/form-async.style.scss
@@ -0,0 +1,15 @@
+.form-wrapper{
+ width:640px;
+ padding-left: 50px;
+ padding-top: 50px;
+ .details-item{
+ padding-bottom: 30px;
+ }
+ .details-item {
+ select {
+ font-family: OpenSans-Italic;
+ font-size: 14px;
+ color: #959595 !important;
+ }
+ }
+}
diff --git a/vid-webpack-master/src/app/components/form-async/form-async.template.html b/vid-webpack-master/src/app/components/form-async/form-async.template.html
new file mode 100644
index 000000000..c63a7bee6
--- /dev/null
+++ b/vid-webpack-master/src/app/components/form-async/form-async.template.html
@@ -0,0 +1,67 @@
+<div class="content">
+ <form #form="ngForm" name="networkNodeForm" class="form-wrapper">
+ <div *ngIf="isUserProvidedNaming" class="details-item">
+ <label class="placeholder">Instance name*</label>
+ <input [attr.data-tests-id]="'instanceName'" id="instance-name" [(ngModel)]="serviceInstance.instanceName" name="instance-name"
+ class="form-control input-text" placeholder="Type Instance Name" type="text" required>
+ </div>
+
+ <div class="details-item">
+ <label>Product family</label>
+ <select class="form-control input-text" [(ngModel)]="serviceInstance.productFamily" data-tests-id="productFamily" id="product-family-select"
+ name="product-family-select">
+ <option class="placeholder" [value]="undefined" disabled>Select Product Family</option>
+ <option *ngFor="let productFamily of productFamilies | async" [value]="productFamily.id" [disabled]="!productFamily.isPermitted">{{productFamily.name}}</option>
+ </select>
+ </div>
+
+ <div class="details-item">
+ <label>LCP region:*</label>
+ <select (change)="onLcpSelect($event.target.value)" class="form-control input-text" [(ngModel)]="serviceInstance.lcpRegion"
+ name="lcpRegion" id="lcpRegion-select" data-tests-id="lcpRegion" required>
+ <option class="placeholder1" [value]="undefined" disabled>Select LCP Region</option>
+ <option *ngFor="let lcpRegion of lcpRegions | async" [value]="lcpRegion.id" [disabled]="!lcpRegion.isPermitted" class="lcpRegionOption">{{lcpRegion.id}}</option>
+ </select>
+ </div>
+ <div class="details-item">
+ <label>Tenant:*</label>
+ <select class="form-control input-text" [(ngModel)]="serviceInstance.tenantId" name="tenant" id="tenant-select" data-tests-id="tenant"
+ required>
+ <option class="placeholder1" [value]="undefined" disabled>Select Tenant</option>
+ <option *ngFor="let tenant of tenants" [value]="tenant.id" [disabled]="!tenant.isPermitted">{{tenant.name}}</option>
+ </select>
+ </div>
+
+ <div class="details-item">
+ <label>AIC Zone:</label>
+ <select class="form-control input-text" name="aicZone" id="aicZone-select" data-tests-id="aic_zone" [(ngModel)]="serviceInstance.aicZone">
+ <option class="placeholder1" [value]="undefined" disabled>Select AIC Zone</option>
+ <option class="aicZoneOption" *ngFor="let aicZone of aicZones | async" [value]="aicZone.id">{{aicZone.name}}</option>
+ </select>
+ </div>
+ <div class="details-item">
+ <label>Platform:</label>
+ <select data-tests-id="platform" class="form-control input-text" name="platform" id="platform" [(ngModel)]="serviceInstance.platformName">
+ <option class="placeholder1" [value]="undefined" disabled>Select Platform</option>
+ <option *ngFor="let platform of platformList | async" [value]="platform.id">{{platform.name}}</option>
+ </select>
+ </div>
+
+ <div class="details-item">
+ <label>Line Of Business:*</label>
+ <select data-tests-id="lineOfBusiness" class="form-control input-text" [(ngModel)]="serviceInstance.lineOfBusiness"
+ name="owningEntity" id="owningEntity" required>
+ <option class="placeholder1" [value]="undefined" disabled>Select Line Of Business</option>
+ <option *ngFor="let lineOfBusiness of lineOfBusinessList | async" [value]="lineOfBusiness.id">{{lineOfBusiness.name}}</option>
+ </select>
+ </div>
+ <div class="details-item">
+ <label>Rollback On Failure:</label>
+ <select data-tests-id="suppressRollback" class="form-control input-text" name="rollbackOnFailure" id="rollbackOnFailure" [(ngModel)]="serviceInstance.rollback">
+ <option *ngFor="let option of rollbackOnFailure" [value]="option.id">{{option.name}}</option>
+ </select>
+ </div>
+ </form>
+
+</div>
+
diff --git a/vid-webpack-master/src/app/components/instance-popup/instance-popup.components.ts b/vid-webpack-master/src/app/components/instance-popup/instance-popup.components.ts
new file mode 100644
index 000000000..b8ce613d4
--- /dev/null
+++ b/vid-webpack-master/src/app/components/instance-popup/instance-popup.components.ts
@@ -0,0 +1,9 @@
+import {ModelInformationItem} from "../../shared/components/model-information/model-information.component";
+
+
+export interface InstancePopup {
+ onCancelClick():void;
+ createModelInformationItems(): Array<ModelInformationItem>;
+ getModelName():string;
+}
+
diff --git a/vid-webpack-master/src/app/components/service-popup/service-instance-details/service-instance-details.component.ts b/vid-webpack-master/src/app/components/service-popup/service-instance-details/service-instance-details.component.ts
new file mode 100644
index 000000000..b6a2e3967
--- /dev/null
+++ b/vid-webpack-master/src/app/components/service-popup/service-instance-details/service-instance-details.component.ts
@@ -0,0 +1,238 @@
+import {Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges, ViewChild} from '@angular/core';
+import {FormControl, FormGroup, Validators} from "@angular/forms";
+import {ServicePopupDataModel} from './servicePopupDataModel';
+import {AaiService} from '../../../services/aaiService/aai.service';
+import {updateServiceInstance} from "../../../service.actions";
+import * as _ from 'lodash';
+import {ServiceModel} from "../../../shared/models/serviceModel";
+import {ModelInfo} from "../../../shared/models/modelInfo";
+import {loadProductFamiliesAction} from "../../../services/aaiService/aai.actions";
+import {Observable} from "rxjs/Observable";
+import {SelectOptionInterface} from "../../../shared/models/selectOption";
+import {NgRedux, select} from "@angular-redux/store";
+import {AppState} from "../../../store/reducers";
+import {isNullOrUndefined} from 'util';
+import {ServiceInstanceDetailsService} from './service-instance-details.service';
+import {NumbersLettersUnderscoreValidator} from '../../../shared/components/validators/numbersLettersUnderscore/numbersLettersUnderscore.validator';
+import {DefaultDataGeneratorService} from '../../../shared/services/defaultDataServiceGenerator/default.data.generator.service';
+
+
+@Component({
+ selector: 'service-instance-details',
+ templateUrl: 'service-instance-details.html',
+ styleUrls: ['service-instance-details.scss'],
+ providers: [AaiService]
+})
+
+export class ServiceInstanceDetailsComponent implements OnInit, OnChanges {
+ ngOnChanges(changes: SimpleChanges): void {
+ if (changes["serviceInstance"] !== undefined && changes["serviceInstance"].currentValue !== changes["serviceInstance"].previousValue && changes["serviceInstance"].currentValue !== null) {
+ this.oldServiceInstance = Object.assign({}, this.serviceInstance);
+ }
+ }
+ _serviceModel: ServiceModel;
+ @Input () serviceInstance: any;
+ @Input () dynamicInputs;
+ @Input () servicesQty: number;
+ @Input ()
+ set serviceModel(serviceModel: ServiceModel) {
+ this._serviceModel = serviceModel;
+ this.updateFormGroupControlsWithServiceModel(serviceModel);
+ }
+ @ViewChild('serviceForm') serviceForm: 'ServiceForm';
+ @Output() closePopup : EventEmitter<any> = new EventEmitter<any>();
+ @Output() onDataChanged: EventEmitter<any> = new EventEmitter<any>();
+ oldServiceInstance = {};
+
+ //todo: implement Epics and use @select to fetch the rest of the form's data as done with productFamilies.
+ //that way we can loose the updateFormData function and the subscription to store in the constructor.
+ @select(['service','productFamilies'])
+ readonly productFamilies : Observable<SelectOptionInterface[]>;
+ serviceDetails:any = {
+
+ };
+ servicePopupDataModel: ServicePopupDataModel = new ServicePopupDataModel();
+ serviceInstanceDetailsFormGroup: FormGroup;
+ serviceInstanceDetailsService : ServiceInstanceDetailsService;
+
+ constructor(private _aaiService: AaiService, private store: NgRedux<AppState>, private _serviceInstanceDetailsService : ServiceInstanceDetailsService, private _defaultDataGeneratorService : DefaultDataGeneratorService) {
+ this.store.subscribe(() => {this.updateFormData()});
+ this.serviceInstanceDetailsService = this._serviceInstanceDetailsService;
+ this.serviceInstanceDetailsFormGroup = this.createFormGroup();
+
+ this.serviceInstanceDetailsFormGroup.valueChanges.subscribe(()=> {
+ this.onDataChanged.next();
+ })
+ }
+
+ ngOnInit() {
+ this.subscribeToFormChanges();
+ this._aaiService.getSubscribers().subscribe();
+ this._aaiService.getCategoryParameters(null).subscribe();
+ this._aaiService.getAicZones().subscribe();
+ this.store.dispatch(loadProductFamiliesAction());
+ }
+
+
+ createFormGroup(): FormGroup {
+ const formGroup = new FormGroup({
+ globalSubscriberId: new FormControl(
+ Validators.compose([Validators.required])
+ ),
+ productFamilyId: new FormControl(),
+ subscriptionServiceType: new FormControl({value: null, disabled: true}, Validators.compose([Validators.required])),
+ lcpCloudRegionId: new FormControl({value: null, disabled: true}, Validators.compose([Validators.required])),
+ tenantId: new FormControl({value: null, disabled: true}, Validators.compose([Validators.required])),
+ aicZoneId: new FormControl(),
+ projectName: new FormControl(),
+ owningEntityId: new FormControl(Validators.compose([Validators.required])),
+ rollbackOnFailure: new FormControl(null, Validators.required),
+ });
+
+ return formGroup;
+ }
+
+ updateFormGroupControlsWithServiceModel(serviceModel: ServiceModel) {
+ this.serviceInstanceDetailsFormGroup.markAsUntouched();
+
+ if (serviceModel) {
+ this.serviceDetails.isUserProvidedNaming = serviceModel.isUserProvidedNaming;
+ if (serviceModel.isUserProvidedNaming) {
+ this.serviceInstanceDetailsFormGroup.addControl('instanceName', new FormControl('', Validators.compose([Validators.required, NumbersLettersUnderscoreValidator.valid])))
+ }else{
+ this.serviceInstanceDetailsFormGroup.removeControl('instanceName');
+ }
+
+ if (serviceModel.isMultiStepDesign) {
+ this.serviceInstanceDetailsFormGroup.addControl('pause', new FormControl(true));
+ }else{
+ this.serviceInstanceDetailsFormGroup.removeControl('pause');
+ }
+ }
+ }
+
+ updateFormData() {
+ let service = this.store.getState().service;
+ this.servicePopupDataModel.subscribers = service.subscribers;
+ this.servicePopupDataModel.serviceTypes = service.serviceTypes[this.servicePopupDataModel.globalCustomerId];
+ this.servicePopupDataModel.lcpRegions = service.lcpRegionsAndTenants.lcpRegionList;
+ if (this.serviceInstance) {
+ this.servicePopupDataModel.tenants = service.lcpRegionsAndTenants.lcpRegionsTenantsMap[this.serviceInstance.lcpCloudRegionId];
+ }
+ this.servicePopupDataModel.aicZones = service.aicZones;
+ this.servicePopupDataModel.owningEntities = _.get(service.categoryParameters, 'owningEntityList');
+ this.servicePopupDataModel.projects = _.get(service.categoryParameters, 'projectList');
+ this.onDataChanged.next();
+ }
+
+ subscribeToFormChanges(): void {
+ this.serviceInstanceDetailsFormGroup.get('globalSubscriberId').valueChanges.subscribe(val => {
+ this.updateServiceTypes(val);
+ this.setDisabledState(val, 'subscriptionServiceType');
+
+ });
+ this.serviceInstanceDetailsFormGroup.get('subscriptionServiceType').valueChanges.subscribe(val => {
+ this.getTenants(val);
+ this.setDisabledState(val, 'lcpCloudRegionId');
+
+ });
+ this.serviceInstanceDetailsFormGroup.get('lcpCloudRegionId').valueChanges.subscribe(val => {
+ this.setDisabledState(val, 'tenantId');
+ this.updateTenantList(val);
+
+ });
+
+ this.serviceInstanceDetailsFormGroup.get('tenantId').valueChanges.subscribe(val => {
+ this.serviceDetails.tenantName = this.getNameFromListById(this.servicePopupDataModel.tenants, val);
+ this.onDataChanged.next();
+ });
+
+ this.serviceInstanceDetailsFormGroup.get('aicZoneId').valueChanges.subscribe(val => {
+ this.serviceDetails.aicZoneName = this.getNameFromListById(this.servicePopupDataModel.aicZones, val);
+ this.onDataChanged.next();
+ });
+ }
+
+ getNameFromListById(list, id:string ) {
+ if(list && id) {
+ let filterItem = list.filter(item => {
+ return item.id == id;
+ })
+ return filterItem && filterItem[0].name;
+ }
+ return null;
+ }
+
+ setDisabledState(val, field: string): void {
+ if(val) {
+ this.serviceInstanceDetailsFormGroup.controls[field].enable();
+ } else {
+ this.serviceInstanceDetailsFormGroup.controls[field].disable();
+ }
+ }
+
+ isShowingNotificationArea(): boolean {
+ return this.servicesQty > 1;
+ }
+
+ updateServiceTypes(subscriberId) {
+ if (subscriberId) {
+ this.servicePopupDataModel.globalCustomerId = subscriberId;
+ this._aaiService.getServiceTypes(subscriberId).subscribe(() => {
+ this.updateFormData();
+ this.onDataChanged.next();
+ }, (error) => {
+
+ });
+ }
+ }
+
+ updateTenantList(cloudRegionId) {
+ this.servicePopupDataModel.tenants = this.store.getState().service.lcpRegionsAndTenants.lcpRegionsTenantsMap[cloudRegionId];
+ this.onDataChanged.next();
+ }
+
+ getTenants(serviceType) {
+ if (serviceType) {
+ this._aaiService.getLcpRegionsAndTenants(this.servicePopupDataModel.globalCustomerId, serviceType).subscribe(()=>{
+ this.onDataChanged.next();
+ });
+ }
+ }
+
+ onSubmit(formValues): void {
+ formValues.bulkSize = this.servicesQty;
+ let dynamicFields: { [dynamicField: string] : string; };
+ dynamicFields = {};
+ this.dynamicInputs.map(function (x) {
+ let dynamicField: string = x.id;
+ dynamicFields[dynamicField] = formValues[dynamicField];
+ delete formValues[dynamicField];
+ });
+ formValues.instanceParams = [];
+ formValues.instanceParams.push(dynamicFields);
+ formValues.modelInfo = new ModelInfo(this._serviceModel);
+ Object.assign(formValues, this.serviceDetails);
+ this.store.dispatch(updateServiceInstance(formValues, this._serviceModel.uuid));
+ if (this.store.getState().global.flags['FLAG_SETTING_DEFAULTS_IN_DRAWING_BOARD']){
+ this._defaultDataGeneratorService.updateReduxOnFirstSet(this._serviceModel.uuid,formValues);
+ }
+ window.parent.postMessage( {
+ eventId: 'submitIframe',
+ data: {
+ serviceModelId: this._serviceModel.uuid
+ }
+ }, "*");
+ this.closePopup.emit(this._serviceModel.uuid);
+ }
+
+ hasApiError(controlName : string, data : Array<any>){
+ if(!isNullOrUndefined(this.servicePopupDataModel) && !isNullOrUndefined(data)){
+ if(!this.serviceInstanceDetailsFormGroup.controls[controlName].disabled && data.length === 0){
+ return true;
+ }
+ }
+ return false;
+ }
+
+}
diff --git a/vid-webpack-master/src/app/components/service-popup/service-instance-details/service-instance-details.html b/vid-webpack-master/src/app/components/service-popup/service-instance-details/service-instance-details.html
new file mode 100644
index 000000000..3d632bd89
--- /dev/null
+++ b/vid-webpack-master/src/app/components/service-popup/service-instance-details/service-instance-details.html
@@ -0,0 +1,168 @@
+
+<div id="service-instance-details">
+ <form id="serviceForm" #serviceForm="ngForm" (ngSubmit)="onSubmit(serviceForm.value)" [formGroup]="serviceInstanceDetailsFormGroup">
+ <!--We can't use [hidden] since bootstrap.css label has display: inline-block. -->
+ <!--see https://stackoverflow.com/questions/34650410/angular-2-hidden-does-not-seem-to-be-working-->
+ <label id="notification-area" *ngIf="isShowingNotificationArea()">Data entered will apply to all service instances</label>
+
+ <div class="details-item" *ngIf="serviceInstanceDetailsFormGroup.get('instanceName')">
+ <label class="required">Instance name:</label>
+ <input patternInput
+ pattern="^[a-zA-Z0-9_]*$"
+ [attr.data-tests-id]="'instanceName'"
+ id="instance-name"
+ name="instance-name"
+ [ngClass]="{'error-style' :(serviceInstance?.instanceName != '' && serviceInstanceDetailsFormGroup.controls['instanceName']?.touched && serviceInstanceDetailsFormGroup.controls['instanceName']?.errors?.pattern !== null)}"
+ [formControlName]="'instanceName'"
+ class="form-control input-text"
+ placeholder="Type Instance Name"
+ type="text"
+ [(ngModel)]="serviceInstance.instanceName" required>
+ <form-control-error
+ *ngIf="serviceInstance?.instanceName != '' && serviceInstanceDetailsFormGroup.controls['instanceName']?.touched && serviceInstanceDetailsFormGroup.controls['instanceName']?.errors?.pattern !== null"
+ [message]="'Instance name may include only alphanumeric characters and underscore.'"></form-control-error>
+
+ </div>
+
+ <div class="details-item">
+ <label class="required">Subscriber name:</label>
+ <select class="subscriber form-control input-text" id="subscriber-name-select" data-tests-id="subscriberName"
+ name="subscriber-name-select" [formControlName]="'globalSubscriberId'"
+ [ngClass]="{'error-style' :serviceInstanceDetailsService.hasApiError('globalSubscriberId',servicePopupDataModel?.subscribers, serviceInstanceDetailsFormGroup)}"
+ [(ngModel)]="serviceInstance.globalSubscriberId"
+ required>
+ <option [value]="undefined" disabled>Select Subscriber Name</option>
+ <option class="subscriberNameOption" *ngFor="let subscriber of servicePopupDataModel.subscribers"
+ [value]="subscriber.id" [disabled]="!subscriber.isPermitted">{{subscriber.name}}</option>
+ </select>
+ <form-control-error *ngIf="serviceInstanceDetailsService.hasApiError('globalSubscriberId',servicePopupDataModel?.subscribers, serviceInstanceDetailsFormGroup)" [message]="'No results for this request. Please change criteria.'"></form-control-error>
+
+ </div>
+
+ <div class="details-item">
+ <label class="required">Service type:</label>
+ <select class="form-control input-text"
+ [(ngModel)]="serviceInstance.subscriptionServiceType"
+ [formControlName]="'subscriptionServiceType'"
+ [ngClass]="{'error-style' :serviceInstanceDetailsService.hasApiError('subscriptionServiceType',servicePopupDataModel?.serviceTypes, serviceInstanceDetailsFormGroup)}"
+ data-tests-id="serviceType" id="service-type-select"
+ name="service-type" required>
+ <option [value]="undefined" disabled>Select Service Type</option>
+ <option *ngFor="let serviceType of servicePopupDataModel.serviceTypes" class="serviceTypeOption" [value]="serviceType.name" [disabled]="!serviceType.isPermitted">{{serviceType.name}}</option>
+ </select>
+ <form-control-error *ngIf="serviceInstanceDetailsService.hasApiError('subscriptionServiceType',servicePopupDataModel?.serviceTypes, serviceInstanceDetailsFormGroup)" [message]="'No results for this request. Please change criteria.'"></form-control-error>
+ </div>
+
+ <div class="details-item">
+ <label class="required">Product family:</label>
+ <select class="form-control input-text"
+ data-tests-id="productFamily"
+ id="product-family-select"
+ [ngClass]="{'error-style' :serviceInstanceDetailsService.hasApiError('productFamilyId',productFamilies, serviceInstanceDetailsFormGroup)}"
+ [formControlName]="'productFamilyId'"
+ [(ngModel)]="serviceInstance.productFamilyId"
+ name="product-family-select" required>
+ <option [value]="undefined" disabled>Select Product Family</option>
+ <option *ngFor="let productFamily of productFamilies | async" [value]="productFamily.id"
+ [disabled]="!productFamily.isPermitted">{{productFamily.name}}</option>
+ </select>
+ <form-control-error *ngIf="serviceInstanceDetailsService.hasApiError('productFamilyId',productFamilies, serviceInstanceDetailsFormGroup)" [message]="'No results for this request. Please change criteria.'"></form-control-error>
+ </div>
+
+ <div class="details-item">
+ <label class="required">LCP region:</label>
+ <select
+ class="form-control input-text"
+ [formControlName]="'lcpCloudRegionId'"
+ [(ngModel)]="serviceInstance.lcpCloudRegionId"
+ [ngClass]="{'error-style ' : serviceInstanceDetailsService.hasApiError('lcpCloudRegionId', servicePopupDataModel?.lcpRegions, serviceInstanceDetailsFormGroup)}"
+ name="lcpRegion"
+ id="lcpRegion-select"
+ data-tests-id="lcpRegion"
+ required>
+ <option [value]="undefined" disabled>Select LCP Region</option>
+ <option *ngFor="let lcpRegion of servicePopupDataModel.lcpRegions" [value]="lcpRegion.id" [disabled]="!lcpRegion.isPermitted" class="lcpRegionOption">{{lcpRegion.id}}</option>
+ </select>
+ <form-control-error *ngIf="serviceInstanceDetailsService.hasApiError('lcpCloudRegionId', servicePopupDataModel?.lcpRegions, serviceInstanceDetailsFormGroup)" [message]="'No results for this request. Please change criteria.'"></form-control-error>
+ </div>
+
+ <div class="details-item">
+ <label class="required">Tenant:</label>
+ <select class="form-control input-text"
+ [formControlName]="'tenantId'"
+ [(ngModel)]="serviceInstance.tenantId"
+ name="tenant" id="tenant-select"
+ [ngClass]="{'error-style ' : serviceInstanceDetailsService.hasApiError('tenantId',servicePopupDataModel?.tenants ,serviceInstanceDetailsFormGroup)}"
+ data-tests-id="tenant" required>
+ <option [value]="undefined" disabled>Select Tenant</option>
+ <option *ngFor="let tenant of servicePopupDataModel.tenants" [value]="tenant.id" [disabled]="!tenant.isPermitted">{{tenant.name}}</option>
+ </select>
+ <form-control-error *ngIf="serviceInstanceDetailsService.hasApiError('tenantId',servicePopupDataModel?.tenants ,serviceInstanceDetailsFormGroup)" [message]="'No results for this request. Please change criteria.'"></form-control-error>
+ </div>
+
+ <div class="details-item">
+ <label>AIC Zone:</label>
+ <select
+ class="form-control input-text"
+ name="aicZone" id="aicZone-select"
+ data-tests-id="aic_zone"
+ [formControlName]="'aicZoneId'"
+ [ngClass]="{'error-style ' : servicePopupDataModel?.aicZones?.length == 0 && serviceInstanceDetailsFormGroup.controls['aicZoneId'].disabled == false}"
+ [(ngModel)]="serviceInstance.aicZoneId" >
+ <option [value]="undefined" disabled>Select AIC Zone</option>
+ <option class="aicZoneOption" *ngFor="let aicZone of servicePopupDataModel.aicZones" [value]="aicZone.id">{{aicZone.name}}</option>
+ </select>
+ <form-control-error *ngIf="serviceInstanceDetailsService.hasApiError('aicZoneId',servicePopupDataModel?.aicZones ,serviceInstanceDetailsFormGroup)" [message]="'No results for this request. Please change criteria.'"></form-control-error>
+
+ </div>
+
+ <div class="details-item">
+ <label>Project:</label>
+ <select
+ [attr.data-tests-id]="'project'"
+ class="form-control input-text"
+ [ngClass]="{'error-style ' : servicePopupDataModel?.projects?.length == 0 && serviceInstanceDetailsFormGroup.controls['projectName'].disabled == false}"
+ name="project" id="project"
+ [formControlName]="'projectName'"
+ [(ngModel)]="serviceInstance.projectName" >
+ <option [value]="undefined" disabled>Select Project</option>
+ <option *ngFor="let project of servicePopupDataModel.projects" [value]="project.id">{{project.name}}</option>
+ </select>
+ <form-control-error *ngIf="serviceInstanceDetailsService.hasApiError('projectName',servicePopupDataModel?.projects ,serviceInstanceDetailsFormGroup)" [message]="'No results for this request. Please change criteria.'"></form-control-error>
+
+ </div>
+
+ <div class="details-item">
+ <label class="required">Owning entity:</label>
+ <select [attr.data-tests-id]="'owningEntity'"
+ class="form-control input-text"
+ [formControlName]="'owningEntityId'"
+ [(ngModel)]="serviceInstance.owningEntityId"
+ name="owningEntity" id="owningEntity"
+ [ngClass]="{'error-style ' : servicePopupDataModel?.owningEntities?.length == 0 && serviceInstanceDetailsFormGroup.controls['owningEntityId'].disabled == false}"
+ required>
+ <option [value]="undefined" disabled>Select Owning Entity</option>
+ <option *ngFor="let owningEntity of servicePopupDataModel.owningEntities" [value]="owningEntity.id">{{owningEntity.name}}</option>
+ </select>
+ <form-control-error *ngIf="serviceInstanceDetailsService.hasApiError('owningEntityId',servicePopupDataModel?.owningEntities ,serviceInstanceDetailsFormGroup)" [message]="'No results for this request. Please change criteria.'"></form-control-error>
+ </div>
+ <div class="details-item">
+ <label class="required">Rollback On Failure:</label>
+ <select [attr.data-tests-id]="'rollback'"
+ [ngClass]="{'error-style' :serviceInstanceDetailsService.hasApiError('rollbackOnFailure',servicePopupDataModel?.rollbackOnFailure, serviceInstanceDetailsFormGroup)}"
+ class="form-control input-text"
+ [(ngModel)]="serviceInstance.rollbackOnFailure"
+ [formControlName]="'rollbackOnFailure'" name="rollbackOnFailure" id="rollbackOnFailure">
+ <option *ngFor="let option of servicePopupDataModel.rollbackOnFailure" [value]="option.id">{{option.name}}</option>
+ </select>
+ <form-control-error *ngIf="serviceInstanceDetailsService.hasApiError('rollbackOnFailure',servicePopupDataModel?.rollbackOnFailure, serviceInstanceDetailsFormGroup)" [message]="'No results for this request. Please change criteria.'"></form-control-error>
+ </div>
+ <div class="details-item" *ngIf="serviceInstanceDetailsFormGroup.get('pause')">
+ <input #pause id="pause" [formControlName]="'pause'" [(ngModel)]="serviceInstance.pause" type="checkbox" name="pause" data-toggle="toggle">
+ <label class="checkbox-label" for="pause">Pause on pause points:</label>
+ </div>
+
+
+ <dynamic-inputs *ngIf="dynamicInputs != undefined && dynamicInputs.length>0" [group]="serviceInstanceDetailsFormGroup" [list]="dynamicInputs"></dynamic-inputs>
+ </form>
+</div>
diff --git a/vid-webpack-master/src/app/components/service-popup/service-instance-details/service-instance-details.scss b/vid-webpack-master/src/app/components/service-popup/service-instance-details/service-instance-details.scss
new file mode 100644
index 000000000..928343d43
--- /dev/null
+++ b/vid-webpack-master/src/app/components/service-popup/service-instance-details/service-instance-details.scss
@@ -0,0 +1,64 @@
+#service-instance-details {
+ position: relative;
+
+ #notification-area {
+ color: #959595;
+ font-size: 12px;
+ position: absolute;
+ top: 3px;
+ left: 30px;
+ }
+
+ height: 100%;
+ overflow: auto;
+ padding: 30px;
+
+ /deep/ {
+ .form-control {
+ border-radius: 2px;
+ box-shadow: none;
+ border-color: #D2D2D2;
+ }
+
+ label {
+ font-family: OpenSans-Semibold;
+ font-size: 12px;
+ }
+
+ select {
+ @extend .form-control;
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ appearance: none;
+ background: url('../../../../assets/img/chevron.svg') 0 0 no-repeat;
+ background-size: 24px;
+ background-position-x: right;
+ background-position-y: center;
+ font-family: OpenSans-Italic;
+ font-size: 14px;
+ color: #959595;
+ height: 38px;
+ }
+
+ input:not([type='checkbox']) {
+ @extend .form-control;
+ height: 38px;
+ }
+
+ .form-control[disabled], fieldset[disabled] .form-control {
+ opacity: 0.5;
+ }
+ .input-text {
+ border: 1px solid #D2D2D2;
+ border-radius: 2px;
+ }
+
+ .details-item {
+ margin-bottom: 20px;
+ }
+ }
+
+ .checkbox-label {
+ font-family: OpenSans-Regular;
+ }
+}
diff --git a/vid-webpack-master/src/app/components/service-popup/service-instance-details/service-instance-details.service.spec.ts b/vid-webpack-master/src/app/components/service-popup/service-instance-details/service-instance-details.service.spec.ts
new file mode 100644
index 000000000..605653bd0
--- /dev/null
+++ b/vid-webpack-master/src/app/components/service-popup/service-instance-details/service-instance-details.service.spec.ts
@@ -0,0 +1,26 @@
+import { getTestBed, TestBed } from '@angular/core/testing';
+import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
+import { ServiceInstanceDetailsService } from './service-instance-details.service';
+import { NgRedux } from '@angular-redux/store';
+
+export class MockAppStore<T> {}
+
+describe('Service instance details service', () => {
+ let injector;
+ let service: ServiceInstanceDetailsService;
+ let httpMock: HttpTestingController;
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({
+ imports: [HttpClientTestingModule],
+ providers: [ServiceInstanceDetailsService,
+ {provide: NgRedux, useClass: MockAppStore}]
+ });
+
+ injector = getTestBed();
+ service = injector.get(ServiceInstanceDetailsService);
+ httpMock = injector.get(HttpTestingController);
+ });
+});
+
+
diff --git a/vid-webpack-master/src/app/components/service-popup/service-instance-details/service-instance-details.service.ts b/vid-webpack-master/src/app/components/service-popup/service-instance-details/service-instance-details.service.ts
new file mode 100644
index 000000000..99b390d2f
--- /dev/null
+++ b/vid-webpack-master/src/app/components/service-popup/service-instance-details/service-instance-details.service.ts
@@ -0,0 +1,22 @@
+import { Injectable } from '@angular/core';
+import { isNullOrUndefined } from 'util';
+import { FormGroup } from '@angular/forms';
+import * as _ from 'lodash';
+import { createVFModuleInstance, updateVFModuleInstance, updateVNFInstance } from '../../../service.actions';
+import { NgRedux } from '@angular-redux/store';
+import { AppState } from '../../../store/reducers';
+
+@Injectable()
+export class ServiceInstanceDetailsService {
+ static controlsFieldsStatus = {};
+
+ constructor(private store: NgRedux<AppState>) { }
+ hasApiError(controlName: string, data: Array<any>, serviceInstanceDetailsFormGroup: FormGroup) {
+ if (!isNullOrUndefined(data)) {
+ if (!serviceInstanceDetailsFormGroup.controls[controlName].disabled && data.length === 0) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/vid-webpack-master/src/app/components/service-popup/service-instance-details/servicePopupDataModel.ts b/vid-webpack-master/src/app/components/service-popup/service-instance-details/servicePopupDataModel.ts
new file mode 100644
index 000000000..c7894e2cd
--- /dev/null
+++ b/vid-webpack-master/src/app/components/service-popup/service-instance-details/servicePopupDataModel.ts
@@ -0,0 +1,32 @@
+import {SelectOption, SelectOptionInterface} from "../../../shared/models/selectOption";
+
+export class ServicePopupDataModel {
+ subscribers: SelectOptionInterface[];
+ serviceTypes: SelectOptionInterface[];
+ aicZones: SelectOptionInterface[];
+ lcpRegions: SelectOptionInterface[];
+ productFamilies: SelectOptionInterface[];
+ lcpRegionsTenantsMap: object;
+ tenants: SelectOptionInterface[];
+ projects: SelectOptionInterface[];
+ owningEntities: SelectOptionInterface[];
+ globalCustomerId: string;
+ rollbackOnFailure: SelectOptionInterface[];
+
+
+ constructor(){
+ this.subscribers = null;
+ this.serviceTypes = null;
+ this.aicZones = null;
+ this.lcpRegions = null;
+ this.lcpRegionsTenantsMap = {};
+ this.tenants = null;
+ this.productFamilies = null;
+ this.projects = null;
+ this.owningEntities = null;
+ this.rollbackOnFailure = [
+ new SelectOption({id: 'true', name: 'Rollback'}),
+ new SelectOption({id: 'false', name: 'Don\'t Rollback'})
+ ];
+ }
+}
diff --git a/vid-webpack-master/src/app/components/service-popup/service-popup.component.ts b/vid-webpack-master/src/app/components/service-popup/service-popup.component.ts
new file mode 100644
index 000000000..908ae4adf
--- /dev/null
+++ b/vid-webpack-master/src/app/components/service-popup/service-popup.component.ts
@@ -0,0 +1,144 @@
+import {Component, ViewChild} from '@angular/core';
+import {DialogComponent, DialogService} from 'ng2-bootstrap-modal';
+import {ServiceModel} from '../../shared/models/serviceModel';
+import {Constants} from '../../shared/utils/constants';
+import {ServiceInstanceDetailsComponent} from './service-instance-details/service-instance-details.component';
+import {ActivatedRoute} from "@angular/router";
+import {AaiService} from "../../services/aaiService/aai.service";
+import {Utils} from "../../utils/utils";
+import {ServicePlanningService} from "../../services/service-planning.service";
+import * as _ from 'lodash';
+import {ModelInformationItem} from '../../shared/components/model-information/model-information.component';
+import {deleteServiceInstance} from '../../service.actions';
+
+import {InstancePopup} from "../instance-popup/instance-popup.components";
+import {NgRedux} from "@angular-redux/store";
+import {AppState} from "../../store/reducers";
+import {ServicePopupService} from './service-popup.service';
+import {IframeService} from "../../shared/utils/iframe.service";
+
+export interface ServicePopupModel {
+ serviceModel: ServiceModel
+}
+
+@Component({
+ selector: 'service-popup',
+ templateUrl: 'service-popup.html',
+ styleUrls: ['service-popup.scss'],
+ providers: [AaiService, ServicePopupService]
+})
+
+export class ServicePopupComponent extends DialogComponent<ServicePopupModel, boolean>
+ implements ServicePopupModel, InstancePopup{
+ @ViewChild(ServiceInstanceDetailsComponent) serviceInstanceDetails: ServiceInstanceDetailsComponent;
+
+ serviceModel: ServiceModel;
+ serviceModelId: string;
+ serviceInstance: any = {
+ 'rollbackOnFailure' : 'false'
+ };
+ title: string = Constants.ServicePopup.TITLE;
+ dynamicInputs: any[] = null;
+
+ maxServiceQty:number = 50;
+ minServiceQty:number = 1;
+ servicesQty = 1; //default
+ quantityOptions = this.getQuantityOptions();
+
+ modelInformationItems: Array<ModelInformationItem> = [];
+ hasGeneralApiError : boolean = false;
+ parentElementClassName = 'content';
+
+ constructor(dialogService: DialogService, private route: ActivatedRoute, private _aaiService: AaiService,
+ private _iframeService : IframeService,
+ private _servicePlanningService: ServicePlanningService, private store: NgRedux<AppState>, private _servicePopupService : ServicePopupService) {
+ super(dialogService);
+ this.title = Constants.ServicePopup.TITLE;
+ }
+
+ updateGeneralErrorSection() : void {
+ this.hasGeneralApiError = this._servicePopupService.onControlError(this.serviceInstanceDetails, this.serviceInstanceDetails.serviceInstanceDetailsFormGroup);
+ }
+
+
+ ngOnInit() {
+ this.route
+ .queryParams
+ .subscribe(params => {
+ this.serviceModelId = params['serviceModelId'];
+ if(params['isCreate']=="true") {
+ this.store.dispatch(deleteServiceInstance(this.serviceModelId));
+ }
+ this.updateServiceModelById(this.serviceModelId);
+ this.updateInstanceFromStore();
+ });
+ }
+
+ updateInstanceFromStore() {
+ let serviceInstance;
+ if (_.has(this.store.getState().service.serviceInstance, this.serviceModelId)) {
+ serviceInstance = Object.assign({}, this.store.getState().service.serviceInstance[this.serviceModelId]);
+ }
+
+ this.serviceInstance = serviceInstance ? serviceInstance : this.serviceInstance;
+ this.servicesQty = serviceInstance ? serviceInstance.bulkSize : 1;
+ if (serviceInstance && serviceInstance.instanceParams && serviceInstance.instanceParams[0]) {
+ this.dynamicInputs = this.dynamicInputs.map(function (x) {
+ x.value = (serviceInstance.instanceParams[0][x.id]) ? serviceInstance.instanceParams[0][x.id] : x.value;
+ return x;
+ });
+ }
+ }
+
+ updateServiceModelById(serviceModelId) {
+ this._aaiService.getServiceModelById(serviceModelId).subscribe(
+ value => {
+ const convertedModel = Utils.convertModel(value);
+ this.serviceModel = new ServiceModel(convertedModel);
+ let displayInputs = Object.assign({},convertedModel.service.inputs);
+ this.dynamicInputs = _.isEmpty(displayInputs)? [] : this._servicePlanningService.getArbitraryInputs(displayInputs);
+ this.modelInformationItems = this.createModelInformationItems();
+ },
+ error => {console.log('error is ', error)},
+ () => {console.log('completed')}
+ );
+ }
+
+ createModelInformationItems() : Array<ModelInformationItem> {
+ return [
+ new ModelInformationItem("Model version", "modelVersion", [this.serviceModel.version], "", true),
+ new ModelInformationItem("Description", "description", [this.serviceModel.description]),
+ new ModelInformationItem("Category", "category", [this.serviceModel.category]),
+ new ModelInformationItem("UUID", "uuid", [this.serviceModel.uuid], Constants.ServicePopup.TOOLTIP_UUID, true),
+ new ModelInformationItem("Invariant UUID", "invariantUuid", [this.serviceModel.invariantUuid], Constants.ServicePopup.TOOLTIP_INVARIANT_UUID, true),
+ new ModelInformationItem("Service type", "serviceType", [this.serviceModel.serviceType]),
+ new ModelInformationItem("Service role", "serviceRole", [this.serviceModel.serviceRole])
+ ];
+ }
+
+ onCancelClick() {
+ this._iframeService.removeClassCloseModal(this.parentElementClassName);
+ this.dialogService.removeDialog(this);
+ this.serviceInstance = this.serviceInstanceDetails.oldServiceInstance;
+
+ this._servicePopupService.resetDynamicInputs(this.serviceInstanceDetails, this.dynamicInputs);
+ // Delaying the iframe close in few milliseconds.
+ // This should workaround a problem in Selenium tests' that
+ // blocks after click because the iframe goes out before
+ // the driver understands it was clicked. Similar bug is
+ // described here:
+ // - https://github.com/mozilla/geckodriver/issues/611
+ // - https://bugzilla.mozilla.org/show_bug.cgi?id=1223277
+ setTimeout(() => {
+ window.parent.postMessage("closeIframe", "*");
+ }, 15);
+ }
+
+ getModelName(): string {
+ return (this.serviceModel && this.serviceModel.name) || "";
+ }
+
+ getQuantityOptions(){
+ return _.range(this.minServiceQty, this.maxServiceQty + 1);
+ }
+}
diff --git a/vid-webpack-master/src/app/components/service-popup/service-popup.html b/vid-webpack-master/src/app/components/service-popup/service-popup.html
new file mode 100644
index 000000000..e967daa3b
--- /dev/null
+++ b/vid-webpack-master/src/app/components/service-popup/service-popup.html
@@ -0,0 +1,52 @@
+<div id="service-popup" class="modal-dialog">
+ <div class="modal-content">
+ <div class="modal-header">
+ <button type="button" class="close" (click)="onCancelClick()" >&times;</button>
+ <span [attr.data-tests-id]="'create-modal-title'" class="modal-title">{{title}}</span>
+ </div>
+ <div class="modal-body popup-content">
+
+ <div class="header-left">
+ <div>SERVICE MODEL: <span>"{{getModelName()}}"</span></div>
+ </div>
+
+ <div class="header-right">
+ Service Instance Details
+ </div>
+
+ <label class="quantity-label">Qty:</label>
+ <div class="quantity">
+ <select class="quantity-select" [(ngModel)]="servicesQty" name="quantity" id="quantity-select" required>
+ <option *ngFor="let qty of quantityOptions" [value]="qty">{{qty}}</option>
+ </select>
+ </div>
+
+ <div class="service-model">
+
+ <model-information [modelInformationItems]="modelInformationItems"></model-information>
+ </div>
+
+ <div class="service-instance">
+ <service-instance-details [dynamicInputs]="dynamicInputs"
+ [serviceInstance]="serviceInstance"
+ [serviceModel]="serviceModel"
+ [servicesQty]="servicesQty"
+ (onDataChanged)="updateGeneralErrorSection()"
+ (closePopup)="onCancelClick($event)"></service-instance-details>
+ </div>
+
+ </div>
+ <div class="modal-footer row" style="padding: 0">
+ <div class="col-md-6">
+ <div *ngIf="hasGeneralApiError == true">
+ <form-general-error [message]="'Page contains errors. Please see details next to the relevant fields.'"></form-general-error>
+ </div>
+ </div>
+ <div class="col-md-6" style="padding: 15px;padding-right: 35px;">
+ <button [attr.data-tests-id]="'cancelButton'" type="button" class="btn btn-default cancel" (click)="onCancelClick()"><span>Cancel</span></button>
+ <input type="submit" value="Set" form="serviceForm" data-tests-id="service-form-set"
+ class="btn btn-success submit" [disabled]="!serviceInstanceDetails?.serviceForm?.valid">
+ </div>
+ </div>
+ </div>
+</div>
diff --git a/vid-webpack-master/src/app/components/service-popup/service-popup.scss b/vid-webpack-master/src/app/components/service-popup/service-popup.scss
new file mode 100644
index 000000000..aa4552d2f
--- /dev/null
+++ b/vid-webpack-master/src/app/components/service-popup/service-popup.scss
@@ -0,0 +1,185 @@
+$grid-border: 1px #d2d2d2 solid;
+
+#service-popup {
+ color: #191919;
+
+ .left-panel {
+ background: #f2f2f2;
+ border-right: $grid-border;
+ }
+
+ .header-common {
+ height: 100%;
+ align-items: center;
+ display: flex;
+ font-family: OpenSans-Semibold;
+ font-size: 12px;
+ }
+
+ .header-text {
+ padding-left: 30px;
+ @extend .header-common;
+ }
+
+ .header-left {
+ grid-area: header-left;
+ @extend .header-text;
+ @extend .left-panel;
+ border-bottom: $grid-border;
+
+ span {
+ font-family: OpenSans-Regular;
+ font-size: 14px;
+ };
+ }
+
+ .header-right {
+ grid-area: header-right;
+
+ @extend .header-text;
+ border-bottom: $grid-border;
+ }
+
+ .quantity-label {
+ grid-area: quantity-label;
+ @extend .header-common;
+ border-bottom: $grid-border;
+ height: 100%;
+ font-family: OpenSans-Regular;
+ }
+
+ .quantity {
+ grid-area: quantity;
+ border-left: $grid-border;
+ border-bottom: $grid-border;
+ border-top-style: none;
+ font-family: OpenSans-Semibold;
+ text-align: start;
+ text-indent: 10px;
+ }
+
+ .quantity-select {
+ width: 78px;
+ height: 100%;
+ border: 0;
+ background: white;
+ outline: none;
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ appearance: none;
+ background: url('../../../assets/img/chevron.svg') 0 0 no-repeat;
+ background-size: 24px;
+ background-position-x: right;
+ background-position-y: center;
+ }
+ input[type="number"]:hover::-webkit-inner-spin-button {
+ height: 20px;
+ }
+
+ .service-model {
+ grid-area: service-model;
+
+ padding: 30px;
+ overflow: auto;
+ @extend .left-panel;
+ }
+
+ .service-instance {
+ grid-area: service-instance;
+ }
+
+ .popup-content {
+ display: grid;
+ grid-template-columns: 400px auto 30px 93px;
+ grid-template-rows: 50px calc(100vh - 180px);
+ grid-template-areas:
+ "header-left header-right quantity-label quantity"
+ "service-model service-instance service-instance service-instance";
+ padding: 0;
+ }
+}
+
+.modal {
+ background-color: #191919;
+ opacity: 0.8;
+}
+
+.modal-dialog {
+ position: relative;
+ width: auto;
+ margin: 0;
+}
+@media (min-width: 1150px) {
+ .popup-content {
+ grid-template-rows: 30px 680px;
+ }
+}
+
+.modal-content {
+ border-radius: 0;
+ box-shadow: none;
+ border: none;
+}
+
+.modal-footer {
+ .cancel {
+ width: 120px;
+ height: 36px;
+ background: #ffffff;
+ border: 1px solid #009fdb;
+ border-radius: 2px;
+ span {
+ font-family: OpenSans-Regular;
+ font-size: 14px;
+ color: #009fdb;
+ line-height: 16px;
+ }
+ }
+
+ .submit {
+ width: 120px;
+ height: 36px;
+ background: #009fdb;
+ border-radius: 2px;
+ border-color: #009fdb;
+ span {
+ font-family: OpenSans-Regular;
+ font-size: 14px;
+ color: #FFFFFF;
+ line-height: 16px;
+ }
+ }
+}
+
+.modal-header {
+ background-color: #009fdb;
+
+ padding-bottom: 13px;
+ padding-top: 13px;
+ padding-left: 29px;
+ padding-right: 21px;
+
+ .close {
+ font-size: 32px;
+ font-weight: 200;
+ color: #d8d8d8;
+ text-shadow: none;
+ filter: none;
+ opacity: 1;
+ }
+
+ .modal-title {
+ font-family: OpenSans-Regular;
+ font-size: 24px;
+ color: #fff;
+ line-height: 34px;
+ }
+}
+//
+//@media (min-width: 1200px) {
+// .service-model,
+// .service-instance {
+// width: 1050px;
+// margin: 30px auto;
+// }
+//}
diff --git a/vid-webpack-master/src/app/components/service-popup/service-popup.service.spec.ts b/vid-webpack-master/src/app/components/service-popup/service-popup.service.spec.ts
new file mode 100644
index 000000000..cddc6400a
--- /dev/null
+++ b/vid-webpack-master/src/app/components/service-popup/service-popup.service.spec.ts
@@ -0,0 +1,138 @@
+
+import { TestBed, getTestBed} from '@angular/core/testing';
+import {
+ HttpClientTestingModule,
+ HttpTestingController
+} from '@angular/common/http/testing';
+import { ServicePopupService } from './service-popup.service';
+import { FormControl, FormGroup, Validators } from '@angular/forms';
+import { NumbersLettersUnderscoreValidator } from '../../shared/components/validators/numbersLettersUnderscore/numbersLettersUnderscore.validator';
+
+describe('Service Popup Service', () => {
+ let injector;
+ let service: ServicePopupService;
+ let httpMock: HttpTestingController;
+ let form : FormGroup;
+ let servicePopupDataModel;
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({
+ imports: [HttpClientTestingModule],
+ providers: [ServicePopupService]
+ });
+
+ injector = getTestBed();
+ service = injector.get(ServicePopupService);
+ httpMock = injector.get(HttpTestingController);
+
+ form = generateFormGroup();
+ servicePopupDataModel = generateServicePopupDataModel();
+ });
+
+ describe('#resetDynamicInputs', () => {
+ it('resetDynamicInputs should reset dymanic fields',(done: DoneFn) => {
+ const dynamicInputs = generateDynamicInputs();
+ let serviceForm = generateFormGroup();
+ serviceForm.addControl(dynamicInputs[0].name, new FormControl({value: dynamicInputs[0].value, disabled: false}));
+
+ serviceForm.controls[dynamicInputs[0].name].setValue("diffValue");
+ service.resetDynamicInputs({
+ serviceInstanceDetailsFormGroup : serviceForm,
+ dynamicInputs : dynamicInputs
+ }, dynamicInputs);
+
+ expect(serviceForm.controls[dynamicInputs[0].name].value).toEqual(dynamicInputs[0].value);
+ done();
+ })
+ });
+
+ describe('#onControlError', () => {
+
+ it('should return true if instanceName is illegal', (done: DoneFn) => {
+ form.controls['instanceName'].setValue("illegal - illegal");
+
+ let result : boolean = service.onControlError(<any>servicePopupDataModel, form);
+ expect(result).toBeTruthy();
+ done();
+ });
+
+ it('should return false if instanceName is legal', (done: DoneFn) => {
+
+ form.controls['instanceName'].setValue("legal");
+ let result = service.onControlError(<any>servicePopupDataModel, form);
+ expect(result).toBeFalsy();
+ done();
+ });
+
+ it('should return false if lcpRegions is empty and is disabled', (done: DoneFn) => {
+ servicePopupDataModel.servicePopupDataModel['lcpRegions'] = [];
+ let result = service.onControlError(<any>servicePopupDataModel, form);
+ expect(result).toBeFalsy();
+ done();
+ });
+
+ it('should return true if lcpRegions is empty', (done: DoneFn) => {
+ servicePopupDataModel.servicePopupDataModel['lcpRegions'] = [];
+ form.controls['lcpCloudRegionId'].enable();
+ let result = service.onControlError(<any>servicePopupDataModel, form);
+ expect(result).toBeTruthy();
+ done()
+ });
+ });
+
+
+ function generateDynamicInputs(){
+ return JSON.parse('[{"id":"2017488_adiodvpe0_ASN","type":"string","name":"2017488_adiodvpe0_ASN","value":"AV_vPE","isRequired":true,"description":"AV/PE"}]');
+ }
+
+
+ function generateServicePopupDataModel() {
+ return {
+ "servicePopupDataModel" : JSON.parse('{"subscribers":[{"id":"a9a77d5a-123e-4ca2-9eb9-0b015d2ee0fb","name":"Mobility","isPermitted":false},{"id":"a9a77d5a-123e-4ca2-9eb9-0b015d2ee0fc","name":"PACKET CORE","isPermitted":false},{"id":"e433710f-9217-458d-a79d-1c7aff376d89","name":"USP VOICE","isPermitted":true}],"serviceTypes":[{"id":"0","name":"vFlowLogic","isPermitted":false},{"id":"1","name":"VIRTUAL USP","isPermitted":true},{"id":"2","name":"Mobility","isPermitted":false},{"id":"3","name":"vBNG","isPermitted":false},{"id":"4","name":"vVoiceMail","isPermitted":false},{"id":"5","name":"Nimbus","isPermitted":false},{"id":"6","name":"vSEGW","isPermitted":false},{"id":"7","name":"vVM","isPermitted":false},{"id":"8","name":"vOTA","isPermitted":false},{"id":"9","name":"vMME","isPermitted":false},{"id":"10","name":"vMNS","isPermitted":false},{"id":"11","name":"vSCP","isPermitted":false},{"id":"12","name":"VPMS","isPermitted":false},{"id":"13","name":"vMMSC","isPermitted":false},{"id":"14","name":"SSD","isPermitted":false},{"id":"15","name":"vMOG","isPermitted":false},{"id":"16","name":"FIRSTNET","isPermitted":false},{"id":"17","name":"ACTIVE_CHARGE","isPermitted":false},{"id":"18","name":"vHSS","isPermitted":false}],"aicZones":[{"id":"NFT1","name":"NFTJSSSS-NFT1"},{"id":"JAG1","name":"YUDFJULP-JAG1"},{"id":"YYY1","name":"UUUAIAAI-YYY1"},{"id":"BAN1","name":"VSDKYUTP-BAN1"},{"id":"DKJ1","name":"DKJSJDKA-DKJ1"},{"id":"MCS1","name":"ASACMAMS-MCS1"},{"id":"UIO1","name":"uioclli1-UIO1"},{"id":"RAJ1","name":"YGBIJNLQ-RAJ1"},{"id":"OPA1","name":"opaclli1-OPA1"},{"id":"SDE1","name":"ZXCVBNMA-SDE1"},{"id":"VEN2","name":"FGHJUHIL-VEN2"},{"id":"ORL1","name":"ORLDFLMA-ORL1"},{"id":"JAD1","name":"JADECLLI-JAD1"},{"id":"ZXL1","name":"LWLWCANN-ZXL1"},{"id":"CKL1","name":"CLKSKCKK-CKL1"},{"id":"SDF1","name":"sdfclli1-SDF1"},{"id":"RAD1","name":"RADICAL1-RAD1"},{"id":"KIT1","name":"BHYJFGLN-KIT1"},{"id":"REL1","name":"INGERFGT-REL1"},{"id":"JNL1","name":"CJALSDAC-JNL1"},{"id":"OLK1","name":"OLKOLKLS-OLK1"},{"id":"CHI1","name":"CHILLIWE-CHI1"},{"id":"UUU4","name":"UUUAAAUU-UUU4"},{"id":"TUF1","name":"TUFCLLI1-TUF1"},{"id":"KJN1","name":"CKALDKSA-KJN1"},{"id":"SAM1","name":"SNDGCA64-SAN1"},{"id":"SCK1","name":"SCKSCKSK-SCK1"},{"id":"HJH1","name":"AOEEQQQD-HJH1"},{"id":"HGD1","name":"SDFQWHGD-HGD1"},{"id":"KOR1","name":"HYFLNBVT-KOR1"},{"id":"ATL43","name":"AICLOCID-ATL43"},{"id":"ATL54","name":"AICFTAAI-ATL54"},{"id":"ATL66","name":"CLLIAAII-ATL66"},{"id":"VEL1","name":"BNMLKUIK-VEL1"},{"id":"ICC1","name":"SANJITAT-ICC1"},{"id":"MNT11","name":"WSXEFBTH-MNT11"},{"id":"DEF2","name":"WSBHGTYL-DEF2"},{"id":"MAD11","name":"SDFQWGKL-MAD11"},{"id":"OLG1","name":"OLHOLHOL-OLG1"},{"id":"GAR1","name":"NGFVSJKO-GAR1"},{"id":"SAN22","name":"GNVLSCTL-SAN22"},{"id":"HRG1","name":"HRGHRGGS-HRG1"},{"id":"JCS1","name":"JCSJSCJS-JCS1"},{"id":"DHA12","name":"WSXEDECF-DHA12"},{"id":"HJE1","name":"AOEEWWWD-HJE1"},{"id":"NCA1","name":"NCANCANN-NCA1"},{"id":"IOP1","name":"iopclli1-IOP1"},{"id":"RTY1","name":"rtyclli1-RTY1"},{"id":"KAP1","name":"HIOUYTRQ-KAP1"},{"id":"ZEN1","name":"ZENCLLI1-ZEN1"},{"id":"HKA1","name":"JAKHLASS-HKA1"},{"id":"CQK1","name":"CQKSCAKK-CQK1"},{"id":"SAI1","name":"UBEKQLPD-SAI1"},{"id":"ERT1","name":"ertclli1-ERT1"},{"id":"IBB1","name":"PLMKOIJU-IBB1"},{"id":"TIR2","name":"PLKINHYI-TIR2"},{"id":"HSD1","name":"CHASKCDS-HSD1"},{"id":"SLF78","name":"SDCTLFN1-SLF78"},{"id":"SEE78","name":"SDCTEEE4-SEE78"},{"id":"SAN13","name":"TOKYJPFA-SAN13"},{"id":"SAA78","name":"SDCTAAA1-SAA78"},{"id":"LUC1","name":"ATLDFGYC-LUC1"},{"id":"AMD13","name":"MEMATLAN-AMD13"},{"id":"TOR1","name":"TOROONXN-TOR1"},{"id":"QWE1","name":"QWECLLI1-QWE1"},{"id":"ZOG1","name":"ZOGASTRO-ZOG1"},{"id":"CAL33","name":"CALIFORN-CAL33"},{"id":"SHH78","name":"SDIT1HHH-SHH78"},{"id":"DSA1","name":"LKJHGFDS-DSA1"},{"id":"CLG1","name":"CLGRABAD-CLG1"},{"id":"BNA1","name":"BNARAGBK-BNA1"},{"id":"ATL84","name":"CANTTCOC-ATL84"},{"id":"APP1","name":"WBHGTYUI-APP1"},{"id":"RJN1","name":"RJNRBZAW-RJN1"},{"id":"EHH78","name":"SDCSHHH5-EHH78"},{"id":"mac10","name":"PKGTESTF-mac10"},{"id":"SXB78","name":"SDCTGXB1-SXB78"},{"id":"SAX78","name":"SDCTAXG1-SAX78"},{"id":"SYD1","name":"SYDNAUBV-SYD1"},{"id":"TOK1","name":"TOKYJPFA-TOK1"},{"id":"KGM2","name":"KGMTNC20-KGM2"},{"id":"DCC1b","name":"POIUYTGH-DCC1b"},{"id":"SKK78","name":"SDCTKKK1-SKK78"},{"id":"SGG78","name":"SDCTGGG1-SGG78"},{"id":"SJJ78","name":"SDCTJJJ1-SJJ78"},{"id":"SBX78","name":"SDCTBXG1-SBX78"},{"id":"LAG1","name":"LARGIZON-LAG1"},{"id":"IAA1","name":"QAZXSWED-IAA1"},{"id":"POI1","name":"PLMNJKIU-POI1"},{"id":"LAG1a","name":"LARGIZON-LAG1a"},{"id":"PBL1","name":"PBLAPBAI-PBL1"},{"id":"LAG45","name":"LARGIZON-LAG1a"},{"id":"MAR1","name":"MNBVCXZM-MAR1"},{"id":"HST70","name":"HSTNTX70-HST70"},{"id":"DCC1a","name":"POIUYTGH-DCC1a"},{"id":"TOL1","name":"TOLDOH21-TOL1"},{"id":"LON1","name":"LONEENCO-LON1"},{"id":"SJU78","name":"SDIT1JUB-SJU78"},{"id":"STN27","name":"HSTNTX01-STN27"},{"id":"SSW56","name":"ss8126GT-SSW56"},{"id":"SBB78","name":"SDIT1BBB-SBB78"},{"id":"DCC3","name":"POIUYTGH-DCC3"},{"id":"GNV1","name":"GNVLSCTL-GNV1"},{"id":"WAS1","name":"WASHDCSW-WAS1"},{"id":"TOY1","name":"TORYONNZ-TOY1"},{"id":"STT1","name":"STTLWA02-STT1"},{"id":"STG1","name":"STTGGE62-STG1"},{"id":"SLL78","name":"SDCTLLL1-SLL78"},{"id":"SBU78","name":"SDIT1BUB-SBU78"},{"id":"ATL2","name":"ATLNGANW-ATL2"},{"id":"BOT1","name":"BOTHWAKY-BOT1"},{"id":"SNG1","name":"SNGPSIAU-SNG1"},{"id":"NYC1","name":"NYCMNY54-NYC1"},{"id":"LAG1b","name":"LARGIZON-LAG1b"},{"id":"AMD15","name":"AMDFAA01-AMD15"},{"id":"SNA1","name":"SNANTXCA-SNA1"},{"id":"PLT1","name":"PLTNCA60-PLT1"},{"id":"TLP1","name":"TLPNXM18-TLP1"},{"id":"SDD81","name":"SAIT1DD6-SDD81"},{"id":"DCC1","name":"POIUYTGH-DCC1"},{"id":"DCC2","name":"POIUYTGH-DCC2"},{"id":"OKC1","name":"OKCBOK55-OKC1"},{"id":"PAR1","name":"PARSFRCG-PAR1"},{"id":"TES36","name":"ABCEETES-TES36"},{"id":"COM1","name":"PLMKOPIU-COM1"},{"id":"ANI1","name":"ATLNGTRE-ANI1"},{"id":"SDG78","name":"SDIT1BDG-SDG78"},{"id":"mac20","name":"PKGTESTF-mac20"},{"id":"DSF45","name":"DSFBG123-DSF45"},{"id":"HST25","name":"HSTNTX01-HST25"},{"id":"AMD18","name":"AUDIMA01-AMD18"},{"id":"SAA80","name":"SAIT9AA3-SAA80"},{"id":"SSA56","name":"SSIT2AA7-SSA56"},{"id":"SDD82","name":"SAIT1DD9-SDD82"},{"id":"JCV1","name":"JCVLFLBW-JCV1"},{"id":"SUL2","name":"WERTYUJK-SUL2"},{"id":"PUR1","name":"purelyde-PUR1"},{"id":"FDE55","name":"FDERT555-FDE55"},{"id":"SITE","name":"LONEENCO-SITE"},{"id":"ATL1","name":"ATLNGAMA-ATL1"},{"id":"JUL1","name":"ZXCVBNMM-JUL1"},{"id":"TAT34","name":"TESAAISB-TAT34"},{"id":"XCP12","name":"CHKGH123-XCP12"},{"id":"RAI1","name":"poiuytre-RAI1"},{"id":"HPO1","name":"ATLNGAUP-HPO1"},{"id":"KJF12","name":"KJFDH123-KJF12"},{"id":"SCC80","name":"SAIT9CC3-SCC80"},{"id":"SAA12","name":"SAIT9AF8-SAA12"},{"id":"SAA14","name":"SAIT1AA9-SAA14"},{"id":"ATL35","name":"TTESSAAI-ATL35"},{"id":"CWY1","name":"CWYMOWBS-CWY1"},{"id":"ATL76","name":"TELEPAAI-ATL76"},{"id":"DSL12","name":"DSLFK242-DSL12"},{"id":"ATL53","name":"AAIATLTE-ATL53"},{"id":"SAA11","name":"SAIT9AA2-SAA11"},{"id":"ATL62","name":"TESSASCH-ATL62"},{"id":"AUG1","name":"ASDFGHJK-AUG1"},{"id":"POI22","name":"POIUY123-POI22"},{"id":"SAA13","name":"SAIT1AA9-SAA13"},{"id":"BHY17","name":"BHYTFRF3-BHY17"},{"id":"LIS1","name":"HOSTPROF-LIS1"},{"id":"SIP1","name":"ZXCVBNMK-SIP1"},{"id":"ATL99","name":"TEESTAAI-ATL43"},{"id":"ATL64","name":"FORLOAAJ-ATL64"},{"id":"TAT33","name":"TESAAISA-TAT33"},{"id":"RAD10","name":"INDIPUNE-RAD10"},{"id":"RTW5","name":"BHYTFRY4-RTW5"},{"id":"JGS1","name":"KSJKKKKK-JGS1"},{"id":"ATL98","name":"TEESTAAI-ATL43"},{"id":"WAN1","name":"LEIWANGW-WAN1"},{"id":"ATL44","name":"ATLSANAB-ATL44"},{"id":"RTD2","name":"BHYTFRk4-RTD2"},{"id":"NIR1","name":"ORFLMANA-NIR1"},{"id":"ATL75","name":"SANAAIRE-ATL75"},{"id":"NUM1","name":"QWERTYUI-NUM1"},{"id":"MTN32","name":"MDTWNJ21-MTN32"},{"id":"RTZ4","name":"BHYTFRZ6-RTZ4"},{"id":"ATL56","name":"ATLSANAC-ATL56"},{"id":"AMS1","name":"AMSTNLBW-AMS1"},{"id":"RCT1","name":"AMSTERNL-RCT1"},{"id":"JAN1","name":"ORFLMATT-JAN1"},{"id":"ABC14","name":"TESAAISA-ABC14"},{"id":"TAT37","name":"TESAAISD-TAT37"},{"id":"MIC54","name":"MICHIGAN-MIC54"},{"id":"ABC11","name":"ATLSANAI-ABC11"},{"id":"AMF11","name":"AMDOCS01-AMF11"},{"id":"ATL63","name":"ATLSANEW-ATL63"},{"id":"ABC12","name":"ATLSECIA-ABC12"},{"id":"MTN20","name":"MDTWNJ21-MTN20"},{"id":"ABC15","name":"AAITESAN-ABC15"},{"id":"AVT1","name":"AVTRFLHD-AVT1"},{"id":"ATL34","name":"ATLSANAI-ATL34"}],"lcpRegions":[{"id":"AAIAIC25","name":"AAIAIC25","isPermitted":true},{"id":"mtn6","name":"mtn6","isPermitted":true}],"lcpRegionsTenantsMap":{},"tenants":[{"id":"bae71557c5bb4d5aac6743a4e5f1d054","name":"AIN Web Tool-15-D-testgamma","isPermitted":true},{"id":"229bcdc6eaeb4ca59d55221141d01f8e","name":"AIN Web Tool-15-D-STTest2","isPermitted":true},{"id":"1178612d2b394be4834ad77f567c0af2","name":"AIN Web Tool-15-D-SSPtestcustome","isPermitted":true},{"id":"19c5ade915eb461e8af52fb2fd8cd1f2","name":"AIN Web Tool-15-D-UncheckedEcopm","isPermitted":true},{"id":"de007636e25249238447264a988a927b","name":"AIN Web Tool-15-D-dfsdf","isPermitted":true},{"id":"62f29b3613634ca6a3065cbe0e020c44","name":"AIN/SMS-16-D-Multiservices1","isPermitted":true},{"id":"649289e30d3244e0b48098114d63c2aa","name":"AIN Web Tool-15-D-SSPST66","isPermitted":true},{"id":"3f21eeea6c2c486bba31dab816c05a32","name":"AIN Web Tool-15-D-ASSPST47","isPermitted":true},{"id":"f60ce21d3ee6427586cff0d22b03b773","name":"CESAR-100-D-sspjg67246","isPermitted":true},{"id":"8774659e425f479895ae091bb5d46560","name":"CESAR-100-D-sspjg68359","isPermitted":true},{"id":"624eb554b0d147c19ff8885341760481","name":"AINWebTool-15-D-iftach","isPermitted":true},{"id":"214f55f5fc414c678059c383b03e4962","name":"CESAR-100-D-sspjg612401","isPermitted":true},{"id":"c90666c291664841bb98e4d981ff1db5","name":"CESAR-100-D-sspjg621340","isPermitted":true},{"id":"ce5b6bc5c7b348e1bf4b91ac9a174278","name":"sspjg621351cloned","isPermitted":true},{"id":"b386b768a3f24c8e953abbe0b3488c02","name":"AINWebTool-15-D-eteancomp","isPermitted":true},{"id":"dc6c4dbfd225474e9deaadd34968646c","name":"AINWebTool-15-T-SPFET","isPermitted":true},{"id":"02cb5030e9914aa4be120bd9ed1e19eb","name":"AINWebTool-15-X-eeweww","isPermitted":true},{"id":"f2f3830e4c984d45bcd00e1a04158a79","name":"CESAR-100-D-spjg61909","isPermitted":true},{"id":"05b91bd5137f4929878edd965755c06d","name":"CESAR-100-D-sspjg621512cloned","isPermitted":true},{"id":"7002fbe8482d4a989ddf445b1ce336e0","name":"AINWebTool-15-X-vdr","isPermitted":true},{"id":"4008522be43741dcb1f5422022a2aa0b","name":"AINWebTool-15-D-ssasa","isPermitted":true},{"id":"f44e2e96a1b6476abfda2fa407b00169","name":"AINWebTool-15-D-PFNPT","isPermitted":true},{"id":"b69a52bec8a84669a37a1e8b72708be7","name":"AINWebTool-15-X-vdre","isPermitted":true},{"id":"fac7d9fd56154caeb9332202dcf2969f","name":"AINWebTool-15-X-NONPODECOMP","isPermitted":true},{"id":"2d34d8396e194eb49969fd61ffbff961","name":"DN5242-Nov16-T5","isPermitted":true},{"id":"cb42a77ff45b48a8b8deb83bb64acc74","name":"ro-T11","isPermitted":true},{"id":"fa45ca53c80b492fa8be5477cd84fc2b","name":"ro-T112","isPermitted":true},{"id":"4914ab0ab3a743e58f0eefdacc1dde77","name":"DN5242-Nov21-T1","isPermitted":true},{"id":"d0a3e3f2964542259d155a81c41aadc3","name":"test-mtn6-09","isPermitted":true},{"id":"cbb99fe4ada84631b7baf046b6fd2044","name":"DN5242-Nov16-T3","isPermitted":true}],"productFamilies":null,"projects":[{"id":"DFW","name":"DFW"},{"id":"x1","name":"x1"},{"id":"yyy1","name":"yyy1"}],"owningEntities":[{"id":"aaa1","name":"aaa1"},{"id":"d61e6f2d-12fa-4cc2-91df-7c244011d6fc","name":"MetroPacketCore"},{"id":"Wireline","name":"Wireline"}],"globalCustomerId":"e433710f-9217-458d-a79d-1c7aff376d89"}')}
+ }
+
+ function generateFormGroup(){
+ return new FormGroup({
+ globalSubscriberId: new FormControl(
+ Validators.compose([Validators.required])
+ ),
+ productFamilyId: new FormControl(),
+ subscriptionServiceType: new FormControl({value: null, disabled: true}, Validators.compose([Validators.required])),
+ lcpCloudRegionId: new FormControl({value: null, disabled: true}, Validators.compose([Validators.required])),
+ tenantId: new FormControl({value: null, disabled: true}, Validators.compose([Validators.required])),
+ aicZoneId: new FormControl(),
+ projectName: new FormControl(),
+ owningEntityId: new FormControl(Validators.compose([Validators.required])),
+ instanceName : new FormControl({value: null}, Validators.compose([Validators.required, NumbersLettersUnderscoreValidator.valid]))
+ });
+ }
+
+
+ function generateServiceInstanceDetails(){
+ return {
+ servicePopupDataModel : {
+ "productFamilies" : []
+ },
+ serviceInstanceDetailsFormGroup : {
+ controls : {
+ productFamilyId : {
+ disabled : false
+ }
+ }
+ }
+ }
+ }
+
+ function generateLegalServiceInstance(){
+ return {
+ instanceName : "legalInstanceName"
+ }
+ }
+
+ function generateIllegalServiceInstance(){
+ return {
+ instanceName : "illegalInstanceName"
+ }
+ }
+
+});
diff --git a/vid-webpack-master/src/app/components/service-popup/service-popup.service.ts b/vid-webpack-master/src/app/components/service-popup/service-popup.service.ts
new file mode 100644
index 000000000..f6efd353b
--- /dev/null
+++ b/vid-webpack-master/src/app/components/service-popup/service-popup.service.ts
@@ -0,0 +1,33 @@
+import {Injectable} from '@angular/core';
+import {isNullOrUndefined} from "util";
+import {NumbersLettersUnderscoreValidator} from '../../shared/components/validators/numbersLettersUnderscore/numbersLettersUnderscore.validator';
+import {ServiceInstanceDetailsComponent} from './service-instance-details/service-instance-details.component';
+import {FormGroup} from '@angular/forms';
+import * as _ from "lodash";
+
+@Injectable()
+export class ServicePopupService {
+ onControlError(serviceInstanceDetails : ServiceInstanceDetailsComponent, serviceInstanceDetailsFormGroup : FormGroup) : boolean{
+ if(!isNullOrUndefined(serviceInstanceDetailsFormGroup) && !isNullOrUndefined(serviceInstanceDetailsFormGroup.controls['instanceName']) && NumbersLettersUnderscoreValidator.valid(serviceInstanceDetailsFormGroup.controls['instanceName'].value) && serviceInstanceDetailsFormGroup.controls['instanceName'].value != null && serviceInstanceDetailsFormGroup.controls['instanceName'].value.length > 0){
+ return true;
+ }
+
+ const controlName : Array<string> = ['productFamilyId', 'lcpCloudRegionId', 'tenantId', 'owningEntityId', 'projectName', 'aicZoneId', 'subscriptionServiceType', 'globalSubscriberId', 'rollbackOnFailure'];
+ const selectDataName : Array<string> = ['productFamilies', 'lcpRegions', 'tenants', 'owningEntities', 'projects', 'aicZones', 'serviceTypes', 'subscribers', 'rollbackOnFailure'];
+ for(let i = 0 ; i < controlName.length ; i++){
+ if (!isNullOrUndefined(serviceInstanceDetails.servicePopupDataModel) && !isNullOrUndefined(serviceInstanceDetails.servicePopupDataModel[selectDataName[i]])) {
+ if (!serviceInstanceDetailsFormGroup.controls[controlName[i]].disabled && serviceInstanceDetails.servicePopupDataModel[selectDataName[i]].length === 0) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ resetDynamicInputs(serviceInstance : any, defaultDynamicInputs : any) : void {
+ for(let dynamicInput of serviceInstance.dynamicInputs){
+ const defaultDymanicInput = _.find(defaultDynamicInputs, {name:dynamicInput.name});
+ serviceInstance.serviceInstanceDetailsFormGroup.controls[dynamicInput.name].setValue(defaultDymanicInput.value);
+ }
+ }
+}
diff --git a/vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnf-instance-details.component.ts b/vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnf-instance-details.component.ts
new file mode 100644
index 000000000..725e44293
--- /dev/null
+++ b/vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnf-instance-details.component.ts
@@ -0,0 +1,275 @@
+import {Component, EventEmitter, Input, OnInit, Output, ViewChild} from '@angular/core';
+import {FormControl, FormGroup, Validators} from "@angular/forms";
+import {VNFPopupDataModel} from './vnfPopupDataModel';
+import {AaiService} from '../../../services/aaiService/aai.service';
+import { createVFModuleInstance, updateVFModuleInstance, updateVNFInstance } from '../../../service.actions';
+import {VnfInstance} from "../../../shared/models/vnfInstance";
+import {ServiceInstance} from "../../../shared/models/serviceInstance";
+import {VNFModel} from "../../../shared/models/vnfModel";
+import {InputType} from "../../../shared/models/inputTypes";
+import {ModelInfo} from "../../../shared/models/modelInfo";
+import {VfModuleInstance} from "../../../shared/models/vfModuleInstance";
+import {NgRedux, select} from "@angular-redux/store";
+import {AppState} from "../../../store/reducers";
+import {SelectOptionInterface} from "../../../shared/models/selectOption";
+import {Observable} from "rxjs/Observable";
+import {loadProductFamiliesAction} from "../../../services/aaiService/aai.actions";
+import {VnfInstanceDetailsService} from "./vnf-instance-details.service";
+import {isNullOrUndefined} from 'util';
+import {NumbersLettersUnderscoreValidator} from '../../../shared/components/validators/numbersLettersUnderscore/numbersLettersUnderscore.validator';
+import * as _ from "lodash";
+import {ServiceNodeTypes} from "../../../shared/models/ServiceNodeTypes";
+
+@Component({
+ selector: 'vnf-instance-details',
+ templateUrl: 'vnf-instance-details.html',
+ styleUrls: ['vnf-instance-details.scss'],
+ providers: [AaiService]
+})
+
+export class VnfInstanceDetailsComponent implements OnInit {
+ @ViewChild('vnfForm') vnfForm: 'VnfForm';
+ _vnfModel: VNFModel;
+ @Input ()
+ set vnfModel(vnfModel: VNFModel) {
+ this._vnfModel = vnfModel;
+ this.updateFormGroupControlsFromVNFModel();
+ }
+ @Input() vnfInstance: any;
+ @Input() serviceInstance: ServiceInstance;
+ @Input() dynamicInputs;
+ @Input() modelName: string;
+ @Input() serviceUuid: string;
+ @Input() userProvidedNaming: boolean;
+ _modelType: string;
+ @Input()
+ set modelType(modelType: string) {
+ this._modelType = modelType;
+ this.updateFormGroupControlsFromVNFModel();
+ }
+
+ @Input() parentModelName: string;
+ @Input() isNewVfModule : boolean;
+
+
+ @Output() onSubmitClick: EventEmitter<any> = new EventEmitter<any>();
+ @Output() onServiceInstanceNameChanged : EventEmitter<boolean> = new EventEmitter<boolean>();
+ @Output() onVolumeGroupNameChanged : EventEmitter<boolean> = new EventEmitter<boolean>();
+
+@Output() onDataChanged: EventEmitter<any> = new EventEmitter<any>();
+ @select(['service','productFamilies'])
+ readonly productFamilies : Observable<SelectOptionInterface[]>;
+
+ vnfPopupDataModel: VNFPopupDataModel = new VNFPopupDataModel();
+ lcpRegionsThatEnableLegacyRegionField = ['AAIAIC25', 'rdm3', 'rdm5a'];
+ shouldShowLegacyRegion: boolean;
+ instanceFormGroup: FormGroup = null;
+ inputType = InputType;
+ isNotUniqueInstanceName : boolean = false;
+ isNotUniqueVolumeGroupName : boolean = false;
+
+ constructor(private _aaiService: AaiService, private store: NgRedux<AppState>,
+ private _vnfInstanceDetailsService : VnfInstanceDetailsService) {
+ this.store.subscribe(() => {
+ this.updateFormData()
+ });
+ }
+
+ ngOnInit() {
+ this.updateFormGroup();
+ this.subscribeToFormChanges();
+ this._aaiService.getCategoryParameters(null).subscribe();
+ this._aaiService.getLcpRegionsAndTenants(this.serviceInstance.globalSubscriberId, this.serviceInstance.subscriptionServiceType).subscribe();
+ this.updateLegacyRegionVisibility();
+ this.store.dispatch(loadProductFamiliesAction());
+ }
+
+ isInputShouldBeShown(inputType: any) {
+ let vnfInputs = [InputType.LCP_REGION, InputType.LOB, InputType.TENANT, InputType.PRODUCT_FAMILY, InputType.PLATFORM, InputType.ROLLBACK];
+ let vfInputs = [InputType.VG];
+ let exist = false;
+ if (this._modelType === 'VF') {
+ exist = vnfInputs.indexOf(inputType) > -1;
+ }
+ else {
+ exist = vfInputs.indexOf(inputType) > -1;
+ }
+ return exist;
+ }
+
+ updateFormGroupControlsFromVNFModel() {
+ if (this._vnfModel && this._modelType) {
+ if (this._modelType === ServiceNodeTypes.VF) {
+ const vnfInstance = <VnfInstance>this.vnfInstance;
+ if (this.instanceFormGroup && this.userProvidedNaming
+ && !this.instanceFormGroup.get('instanceName')) {
+ const initialInstanceName = vnfInstance.instanceName || (!isNullOrUndefined(this._vnfModel.name) ? this._vnfModel.name.replace(/[-]/g, "") : this._vnfModel.name);
+ this.instanceFormGroup.addControl('instanceName', new FormControl(initialInstanceName, Validators.compose([Validators.required, NumbersLettersUnderscoreValidator.valid])))
+ }
+ }
+ else if (this._modelType === ServiceNodeTypes.VFmodule) {
+ const vfInstance = <VfModuleInstance>this.vnfInstance;
+ if (this.instanceFormGroup && this.userProvidedNaming && !this.instanceFormGroup.get('instanceName')) {
+ this.instanceFormGroup.addControl('instanceName', new FormControl(vfInstance.instanceName, Validators.required));
+
+ let vfModule = this.extractVfAccordingToVfModuleUuid(this.store.getState(), this._vnfModel.uuid);
+ if (vfModule.volumeGroupAllowed && !this.instanceFormGroup.get('volumeGroupName')) {
+ this.instanceFormGroup.addControl('volumeGroupName', new FormControl(vfInstance.volumeGroupName));
+ }
+ }
+ }
+ }
+ }
+
+ updateFormGroup() {
+ const tenantDisabled = !this.vnfInstance.lcpCloudRegionId;
+
+ if (this._modelType === ServiceNodeTypes.VF) {
+ const vnfInstance = <VnfInstance>this.vnfInstance;
+ this.instanceFormGroup = new FormGroup({
+ productFamilyId: new FormControl(vnfInstance.productFamilyId),
+ lcpCloudRegionId: new FormControl(vnfInstance.lcpCloudRegionId, Validators.required),
+ tenantId: new FormControl({value: vnfInstance.tenantId, disabled: tenantDisabled}, Validators.required),
+ legacyRegion: new FormControl(vnfInstance.legacyRegion),
+ lineOfBusiness: new FormControl(vnfInstance.lineOfBusiness),
+ platformName: new FormControl(vnfInstance.platformName, Validators.required),
+ });
+ }
+ else if (this._modelType === ServiceNodeTypes.VFmodule) {
+ const vfInstance = <VfModuleInstance>this.vnfInstance;
+ this.instanceFormGroup = new FormGroup({
+ });
+ }
+
+ this.instanceFormGroup.valueChanges.subscribe(()=> {
+ this.checkForUniqueInstanceName();
+ this.onDataChanged.next();
+ });
+
+ this.updateFormGroupControlsFromVNFModel();
+ }
+
+ private getParentVnfModel(): VNFModel {
+ const rawModel = _.get(this.store.getState().service.serviceHierarchy[this.serviceUuid], ['vnfs', this.parentModelName]);
+ return new VNFModel(rawModel);
+ }
+
+ extractVfAccordingToVfModuleUuid(state : any,vfModuleUuid : string) {
+ const vnfs = this.store.getState().service.serviceHierarchy[this.serviceUuid].vnfs;
+ const vnfsArray = Object.values(vnfs);
+ for (let i = 0; i<vnfsArray.length;i++){
+ let vfModules = Object.values(vnfsArray[i].vfModules);
+ for (let j = 0; j<vfModules.length;j++){
+ if (vfModules[j].uuid === vfModuleUuid){
+ return vfModules[j];
+ }
+ }
+ }
+ }
+
+ updateFormData() {
+ let service = this.store.getState().service;
+ this.vnfPopupDataModel.lcpRegions = service.lcpRegionsAndTenants.lcpRegionList;
+ if (this.vnfInstance && this.vnfInstance.lcpCloudRegionId) {
+ this.vnfPopupDataModel.tenants = service.lcpRegionsAndTenants.lcpRegionsTenantsMap[this.vnfInstance.lcpCloudRegionId];
+ console.log('setting vnf instances tenant: ' + JSON.stringify(this.vnfPopupDataModel.tenants));
+ }
+ this.vnfPopupDataModel.platforms = service.categoryParameters.platformList;
+ this.vnfPopupDataModel.lineOfBusinesses = service.categoryParameters.lineOfBusinessList;
+ this.onDataChanged.next();
+ }
+
+ subscribeToFormChanges(): void {
+ if (this.instanceFormGroup.get('lcpCloudRegionId') !== null) {
+ this.instanceFormGroup.get('lcpCloudRegionId').valueChanges.subscribe(val => {
+ this.setDisabledState(val, 'tenantId');
+ this.updateTenantList(val);
+ this.updateLegacyRegionVisibility();
+ this.onDataChanged.next();
+ });
+ }
+ }
+
+ setDisabledState(val, field: string): void {
+ if (val) {
+ this.instanceFormGroup.controls[field].enable();
+ }
+ }
+
+ updateLegacyRegionVisibility() {
+ if (this.instanceFormGroup.get('lcpCloudRegionId') !== null) {
+ this.shouldShowLegacyRegion = this.lcpRegionsThatEnableLegacyRegionField.indexOf(this.instanceFormGroup.get('lcpCloudRegionId').value) > -1;
+ if (!this.shouldShowLegacyRegion) {
+ this.instanceFormGroup.controls.legacyRegion.setValue(undefined);
+ }
+ }
+ }
+
+ updateTenantList(cloudRegionId) {
+ this.resetTenantSelection();
+ const tenantsForCloudRegionId = this.store.getState().service.lcpRegionsAndTenants.lcpRegionsTenantsMap[cloudRegionId];
+ console.log('tenants for selected cloud region id: ' + JSON.stringify(tenantsForCloudRegionId));
+ this.vnfPopupDataModel.tenants = tenantsForCloudRegionId;
+ }
+
+ resetTenantSelection() {
+ this.instanceFormGroup.controls.tenantId.setValue(undefined);
+ }
+
+ checkForUniqueInstanceName() {
+ let currentName = !isNullOrUndefined(this.instanceFormGroup.get('instanceName')) ? this.instanceFormGroup.get('instanceName').value : null;
+
+ if(currentName && !this._vnfInstanceDetailsService.isUnique(this.store.getState().service.serviceInstance, this.serviceUuid, currentName, currentName === this.serviceInstance.instanceName) && this.userProvidedNaming){
+ this.isNotUniqueInstanceName = true;
+ this.onServiceInstanceNameChanged.emit(true);
+ }else {
+ this.isNotUniqueInstanceName = false;
+ this.onServiceInstanceNameChanged.emit(false);
+ }
+ }
+
+ checkForUniqueGroupName(){
+ let currentName = this.instanceFormGroup.get('volumeGroupName').value;
+ if( !this._vnfInstanceDetailsService.isUnique(this.store.getState().service.serviceInstance, this.serviceUuid, currentName, currentName === this.serviceInstance['volumeGroupName'])){
+ this.isNotUniqueVolumeGroupName = true;
+ this.onVolumeGroupNameChanged.emit(true);
+ }else {
+ this.isNotUniqueVolumeGroupName = false;
+ this.onVolumeGroupNameChanged.emit(false);
+ }
+ }
+
+ onSubmit(formValues): void {
+ formValues.modelInfo = new ModelInfo(this._vnfModel);
+ if (this._modelType === 'VFmodule') {
+ let dynamicFields: { [dynamicField: string]: string; };
+ dynamicFields = {};
+ if(!_.isEmpty(this.dynamicInputs)) {
+ this.dynamicInputs.map(function (x) {
+ let dynamicField: string = x.id;
+ dynamicFields[dynamicField] = formValues[dynamicField];
+ delete formValues[dynamicField];
+ });
+ }
+ formValues.instanceParams = [];
+ formValues.instanceParams.push(dynamicFields);
+ if(this.isNewVfModule){
+ this.store.dispatch(createVFModuleInstance(formValues, this.modelName, this.serviceUuid));
+ }else {
+ this.store.dispatch(updateVFModuleInstance(formValues, this.modelName, this.serviceUuid));
+ }
+
+ }
+ else {
+ formValues.isUserProvidedNaming = this.userProvidedNaming;
+ this.store.dispatch(updateVNFInstance(formValues, this.modelName, this.serviceUuid));
+ }
+ window.parent.postMessage({
+ eventId: 'submitIframe',
+ data: {
+ serviceModelId: this.serviceUuid
+ }
+ }, "*");
+ this.onSubmitClick.emit(this.serviceUuid);
+ }
+}
diff --git a/vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnf-instance-details.html b/vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnf-instance-details.html
new file mode 100644
index 000000000..ccdaac53b
--- /dev/null
+++ b/vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnf-instance-details.html
@@ -0,0 +1,114 @@
+
+<div id="vnf-instance-details">
+ <form id="vnfForm" #vnfForm="ngForm" (ngSubmit)="onSubmit(vnfForm.value)" [formGroup]="instanceFormGroup">
+
+ <div class="details-item" *ngIf="instanceFormGroup.get('instanceName')">
+ <label class="required">Instance name:</label>
+ <input patternInput
+ pattern="^[a-zA-Z0-9_]*$"
+ [attr.data-tests-id]="'instanceName'"
+ [ngClass]="{'error-style' : _vnfInstanceDetailsService.hasInstanceNameError(instanceFormGroup) || _vnfInstanceDetailsService.hasUniqueError(isNotUniqueInstanceName)}"
+ id="instance-name" name="instance-name"
+ [formControlName]="'instanceName'"
+ class="form-control input-text"
+ placeholder="Type Instance Name"
+ type="text"
+ (blur)="checkForUniqueInstanceName()">
+ <form-control-error *ngIf="_vnfInstanceDetailsService.hasUniqueError(isNotUniqueInstanceName)" [message]="'Instance name is already in use, please pick another name.'"></form-control-error>
+ <form-control-error *ngIf="_vnfInstanceDetailsService.hasInstanceNameError(instanceFormGroup)" [message]="'Instance name may include only alphanumeric characters and underscore.'"></form-control-error>
+ </div>
+
+ <div *ngIf="isInputShouldBeShown(inputType.PRODUCT_FAMILY)" class="details-item">
+ <label>Product family:</label>
+ <select class="form-control input-text"
+ [ngClass]="{'error-style' :_vnfInstanceDetailsService.hasApiError('productFamilyId',productFamilies, instanceFormGroup)}"
+ data-tests-id="productFamily"
+ id="product-family-select"
+ [formControlName]="'productFamilyId'"
+ name="product-family-select" >
+ <option [value]="null" disabled>Select Product Family</option>
+ <option *ngFor="let productFamily of productFamilies | async" [value]="productFamily.id"
+ [disabled]="!productFamily.isPermitted">{{productFamily.name}}</option>
+ </select>
+ <form-control-error *ngIf="_vnfInstanceDetailsService.hasApiError('productFamilyId',productFamilies, instanceFormGroup)" [message]="'No results for this request. Please change criteria.'"></form-control-error>
+ </div>
+
+ <div *ngIf="isInputShouldBeShown(inputType.LCP_REGION)" class="details-item">
+ <label class="required">LCP region:</label>
+ <select
+ [ngClass]="{'error-style' :_vnfInstanceDetailsService.hasApiError('lcpCloudRegionId',vnfPopupDataModel?.lcpRegions, instanceFormGroup)}"
+ class="form-control input-text"
+ [formControlName]="'lcpCloudRegionId'"
+ name="lcpRegion" id="lcpRegion-select"
+ data-tests-id="lcpRegion">
+ <option [value]="null" disabled>Select LCP Region</option>
+ <option *ngFor="let lcpRegion of vnfPopupDataModel.lcpRegions" [value]="lcpRegion.id" [disabled]="!lcpRegion.isPermitted" class="lcpRegionOption">{{lcpRegion.id}}</option>
+ </select>
+ <form-control-error *ngIf="_vnfInstanceDetailsService.hasApiError('lcpCloudRegionId',vnfPopupDataModel?.lcpRegions, instanceFormGroup)" [message]="'No results for this request. Please change criteria.'"></form-control-error>
+ </div>
+
+ <div class="details-item" *ngIf="shouldShowLegacyRegion">
+ <label>Legacy Region:</label>
+ <input
+ [attr.data-tests-id]="'lcpRegionText'"
+ id="legacy-region"
+ name="legacy-region"
+ [formControlName]="'legacyRegion'"
+ class="form-control input-text"
+ placeholder="Type Legacy Region" type="text">
+ </div>
+
+ <div *ngIf="isInputShouldBeShown(inputType.TENANT)" class="details-item">
+ <label class="required">Tenant:</label>
+ <select class="form-control input-text"
+ [ngClass]="{'error-style' :_vnfInstanceDetailsService.hasApiError('tenantId',vnfPopupDataModel?.tenants, instanceFormGroup)}"
+ [formControlName]="'tenantId'"
+ name="tenant" id="tenant-select" data-tests-id="tenant">
+ <option [value]="undefined" disabled>Select Tenant</option>
+ <option *ngFor="let tenant of vnfPopupDataModel.tenants" [value]="tenant.id" [disabled]="!tenant.isPermitted">{{tenant.name}}</option>
+ </select>
+ <form-control-error *ngIf="_vnfInstanceDetailsService.hasApiError('tenantId',vnfPopupDataModel?.tenants, instanceFormGroup)" [message]="'No results for this request. Please change criteria.'"></form-control-error>
+ </div>
+
+ <div *ngIf="isInputShouldBeShown(inputType.LOB)" class="details-item">
+ <label>Line of business:</label>
+ <select [attr.data-tests-id]="'lineOfBusiness'"
+ class="form-control input-text"
+ [ngClass]="{'error-style' :_vnfInstanceDetailsService.hasApiError('lineOfBusiness',vnfPopupDataModel?.lineOfBusinesses, instanceFormGroup)}"
+ name="lineOfBusiness" id="lineOfBusiness"
+ [formControlName]="'lineOfBusiness'">
+ <option [value]="null" disabled>Select Line Of Business</option>
+ <option *ngFor="let project of vnfPopupDataModel.lineOfBusinesses" [value]="project.id">{{project.name}}</option>
+ </select>
+ <form-control-error *ngIf="_vnfInstanceDetailsService.hasApiError('lineOfBusiness',vnfPopupDataModel?.lineOfBusinesses, instanceFormGroup)" [message]="'No results for this request. Please change criteria.'"></form-control-error>
+ </div>
+
+ <div *ngIf="isInputShouldBeShown(inputType.PLATFORM)" class="details-item">
+ <label class="required">Platform:</label>
+ <select
+ [attr.data-tests-id]="'platform'"
+ [ngClass]="{'error-style' :_vnfInstanceDetailsService.hasApiError('platformName',vnfPopupDataModel?.platforms, instanceFormGroup)}"
+ class="form-control input-text"
+ [formControlName]="'platformName'"
+ name="platform" id="platform">
+ <option [value]="null" disabled>Select Platform</option>
+ <option *ngFor="let platform of vnfPopupDataModel.platforms" [value]="platform.id">{{platform.name}}</option>
+ </select>
+ <form-control-error *ngIf="_vnfInstanceDetailsService.hasApiError('platformName',vnfPopupDataModel?.platforms, instanceFormGroup)" [message]="'No results for this request. Please change criteria.'"></form-control-error>
+ </div>
+
+
+ <div *ngIf="isInputShouldBeShown(inputType.VG) && instanceFormGroup.get('volumeGroupName')" class="details-item" >
+ <label class="required">Volume Group Name:</label>
+ <input [attr.data-tests-id]="'volumeGroupName'"
+ id="vgName" name="vgName"
+ [ngClass]="{'error-style' :isNotUniqueVolumeGroupName}"
+ [formControlName]="'volumeGroupName'"
+ class="form-control input-text"
+ placeholder="Type Instance Name" type="text" (blur)="checkForUniqueGroupName()">
+ <form-control-error *ngIf="isNotUniqueVolumeGroupName" [message]="'Volume Group instance name is already in use, please pick another name.'"></form-control-error>
+ </div>
+
+ <dynamic-inputs *ngIf="dynamicInputs != undefined && dynamicInputs.length>0" [group]="instanceFormGroup" [list]="dynamicInputs"></dynamic-inputs>
+ </form>
+</div>
diff --git a/vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnf-instance-details.scss b/vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnf-instance-details.scss
new file mode 100644
index 000000000..080540a57
--- /dev/null
+++ b/vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnf-instance-details.scss
@@ -0,0 +1,64 @@
+#vnf-instance-details {
+ position: relative;
+
+ #notification-area {
+ color: #959595;
+ font-size: 12px;
+ position: absolute;
+ top: 3px;
+ left: 30px;
+ }
+
+ height: 100%;
+ overflow: auto;
+ padding: 30px;
+
+ /deep/ {
+ .form-control {
+ border-radius: 2px;
+ box-shadow: none;
+ border-color: #D2D2D2;
+ }
+
+ label {
+ font-family: OpenSans-Semibold;
+ font-size: 12px;
+ }
+
+ select {
+ @extend .form-control;
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ appearance: none;
+ background: url('../../../../assets/img/chevron.svg') 0 0 no-repeat;
+ background-size: 24px;
+ background-position-x: right;
+ background-position-y: center;
+ font-family: OpenSans-Italic;
+ font-size: 14px;
+ color: #959595;
+ height: 38px;
+ }
+
+ input:not([type='checkbox']) {
+ @extend .form-control;
+ height: 38px;
+ }
+
+ .form-control[disabled], fieldset[disabled] .form-control {
+ opacity: 0.5;
+ }
+ .input-text {
+ border: 1px solid #D2D2D2;
+ border-radius: 2px;
+ }
+
+ .details-item {
+ margin-bottom: 20px;
+ }
+ }
+
+ .checkbox-label {
+ font-family: OpenSans-Regular;
+ }
+}
diff --git a/vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnf-instance-details.service.spec.ts b/vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnf-instance-details.service.spec.ts
new file mode 100644
index 000000000..41ddb4372
--- /dev/null
+++ b/vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnf-instance-details.service.spec.ts
@@ -0,0 +1,241 @@
+import { TestBed, getTestBed } from '@angular/core/testing';
+import {
+ HttpClientTestingModule,
+ HttpTestingController
+} from '@angular/common/http/testing';
+import { VnfInstanceDetailsService } from './vnf-instance-details.service';
+import { FormControl, FormGroup, Validators } from '@angular/forms';
+import { NumbersLettersUnderscoreValidator } from '../../../shared/components/validators/numbersLettersUnderscore/numbersLettersUnderscore.validator';
+
+describe('Vnf Instance Details Service', () => {
+ let injector;
+ let service: VnfInstanceDetailsService;
+ let httpMock: HttpTestingController;
+
+ let SERVICE_ID: string = '1a80c596-27e5-4ca9-b5bb-e03a7fd4c0fd';
+ let serviceHierarchy;
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({
+ imports: [HttpClientTestingModule],
+ providers: [VnfInstanceDetailsService]
+ });
+
+ injector = getTestBed();
+ service = injector.get(VnfInstanceDetailsService);
+ httpMock = injector.get(HttpTestingController);
+ serviceHierarchy = getServiceServiceHierarchy();
+ });
+
+
+ describe('#hasInstanceNameError', ()=> {
+ it('hasInstanceNameError should return true if instanceName is illegal and enabled', (done: DoneFn) => {
+ let form = generateFormGroup();
+ form.controls['instanceName'].setValue('----');
+ form.controls['instanceName'].setErrors({
+ pattern : true
+ });
+ form.controls['instanceName'].markAsTouched();
+ let result = service.hasInstanceNameError(form);
+ expect(result).toBeTruthy();
+ done();
+ });
+
+ it('hasInstanceNameError should return false if instanceName is illegal and enabled and pattern is ok', (done: DoneFn) => {
+ let form = generateFormGroup();
+ form.controls['instanceName'].setValue('----');
+ form.controls['instanceName'].setErrors({
+ otherError : true
+ });
+ form.controls['instanceName'].markAsTouched();
+ let result = service.hasInstanceNameError(form);
+ expect(result).toBeFalsy();
+ done();
+ });
+ });
+
+ describe('#isUnique', () => {
+ it('Create Mode: should return false if instanceName exist', (done: DoneFn) => {
+ serviceHierarchy = getServiceServiceHierarchy();
+ let result = service.isUnique(serviceHierarchy, SERVICE_ID, 'uniqueInstanceName', false);
+ expect(result).toBeFalsy();
+ done();
+ });
+
+ it('Update Mode: should return true if instanceName exist once', (done: DoneFn) => {
+ let result = service.isUnique(serviceHierarchy, SERVICE_ID, 'uniqueInstanceName', true);
+ expect(result).toBeTruthy()
+ done();
+ });
+
+ it('Create Mode: should return true if instanceName not exist', (done: DoneFn) => {
+ let result = service.isUnique(serviceHierarchy, SERVICE_ID, 'uniqueInstanceNameNotExist', false);
+ expect(result).toBeTruthy();
+ done();
+ });
+
+ it('Create Mode: should return false if instanceName exist inside vf modules', (done: DoneFn) => {
+ let result = service.isUnique(serviceHierarchy, SERVICE_ID, 'uniqueInstanceNameVfModule', false);
+ expect(result).toBeFalsy();
+ done();
+ });
+
+ it('Update Mode: should return true if instanceName exist once inside vf modules', (done: DoneFn) => {
+ let result = service.isUnique(serviceHierarchy, SERVICE_ID, 'uniqueInstanceNameVfModule', true);
+ expect(result).toBeTruthy();
+ done();
+ });
+
+ it('Create Mode: should return true if instanceName is not exist at vf modules and vnfs', (done: DoneFn) => {
+ let result = service.isUnique(serviceHierarchy, SERVICE_ID, 'uniqueInstanceNameVfModuleNotExist', false);
+ expect(result).toBeTruthy();
+ done();
+ });
+
+ it('Create Mode: should return false if instanceName exist service name', (done: DoneFn) => {
+ let result = service.isUnique(serviceHierarchy, SERVICE_ID, 'Instance-Name', false);
+ expect(result).toBeFalsy();
+ done();
+ });
+
+ it('Create Mode: should return false if volumeGroupName exist service name', (done: DoneFn) => {
+ let result = service.isUnique(serviceHierarchy, SERVICE_ID, 'volumeGroupNameExist', false);
+ expect(result).toBeFalsy();
+ done();
+ });
+
+ it('Create Mode: should return true if volumeGroupName not exist service name', (done: DoneFn) => {
+ let result = service.isUnique(serviceHierarchy, SERVICE_ID, 'volumeGroupNameNotExist', false);
+ expect(result).toBeTruthy();
+ done();
+ });
+ });
+
+ function getServiceServiceHierarchy() {
+ return JSON.parse(JSON.stringify(
+ {
+ "1a80c596-27e5-4ca9-b5bb-e03a7fd4c0fd": {
+ "vnfs": {
+ "2017-388_ADIOD-vPE 1": {
+ "rollbackOnFailure": "true",
+ "vfModules": {},
+ "instanceParams": [
+ {}
+ ],
+ "productFamilyId": "a4f6f2ae-9bf5-4ed7-b904-06b2099c4bd7",
+ "lcpCloudRegionId": "AAIAIC25",
+ "tenantId": "092eb9e8e4b7412e8787dd091bc58e86",
+ "lineOfBusiness": "zzz1",
+ "platformName": "platform",
+ "instanceName": "uniqueInstanceName",
+ "modelInfo": {
+ "modelInvariantId": "00beb8f9-6d39-452f-816d-c709b9cbb87d",
+ "modelVersionId": "0903e1c0-8e03-4936-b5c2-260653b96413",
+ "modelName": "2017-388_ADIOD-vPE",
+ "modelVersion": "1.0",
+ "modelCustomizationId": "280dec31-f16d-488b-9668-4aae55d6648a",
+ "modelCustomizationName": "2017-388_ADIOD-vPE 1"
+ },
+ "isUserProvidedNaming": true
+ },
+ "2017-388_ADIOD-vPE 0": {
+ "rollbackOnFailure": "true",
+ "vfModules": {},
+ "instanceParams": [
+ {}
+ ],
+ "productFamilyId": null,
+ "lcpCloudRegionId": "mtn6",
+ "tenantId": "1178612d2b394be4834ad77f567c0af2",
+ "lineOfBusiness": "ECOMP",
+ "platformName": "xxx1",
+ "instanceName": "blaaa",
+ "modelInfo": {
+ "modelInvariantId": "72e465fe-71b1-4e7b-b5ed-9496118ff7a8",
+ "modelVersionId": "afacccf6-397d-45d6-b5ae-94c39734b168",
+ "modelName": "2017-388_ADIOD-vPE",
+ "modelVersion": "4.0",
+ "modelCustomizationId": "b3c76f73-eeb5-4fb6-9d31-72a889f1811c",
+ "modelCustomizationName": "2017-388_ADIOD-vPE 0"
+ },
+ "isUserProvidedNaming": true
+ },
+ "2017488_ADIODvPE 0": {
+ "rollbackOnFailure": "true",
+ "vfModules": {
+ "2017488_adiodvpe0..2017488AdiodVpe..ADIOD_vRE_BV..module-1": {
+ "2017488_adiodvpe0..2017488AdiodVpe..ADIOD_vRE_BV..module-1": {
+ "rollbackOnFailure": "true",
+ "instanceName": "uniqueInstanceNameVfModule",
+ "volumeGroupName": "volumeGroupNameExist",
+ "modelInfo": {
+ "modelInvariantId": "7253ff5c-97f0-4b8b-937c-77aeb4d79aa1",
+ "modelVersionId": "25284168-24bb-4698-8cb4-3f509146eca5",
+ "modelName": "2017488AdiodVpe..ADIOD_vRE_BV..module-1",
+ "modelVersion": "6"
+ }
+ }
+ }
+ },
+ "instanceParams": [
+ {}
+ ],
+ "productFamilyId": "ebc3bc3d-62fd-4a3f-a037-f619df4ff034",
+ "lcpCloudRegionId": "mtn6",
+ "tenantId": "19c5ade915eb461e8af52fb2fd8cd1f2",
+ "lineOfBusiness": "zzz1",
+ "platformName": "platform",
+ "instanceName": "2017488_ADIODvPE",
+ "modelInfo": {
+ "modelInvariantId": "72e465fe-71b1-4e7b-b5ed-9496118ff7a8",
+ "modelVersionId": "69e09f68-8b63-4cc9-b9ff-860960b5db09",
+ "modelName": "2017488_ADIODvPE",
+ "modelVersion": "5.0",
+ "modelCustomizationId": "1da7b585-5e61-4993-b95e-8e6606c81e45",
+ "modelCustomizationName": "2017488_ADIODvPE 0"
+ },
+ "isUserProvidedNaming": true
+ }
+ },
+ "instanceParams": [
+ {}
+ ],
+ "globalSubscriberId": "e433710f-9217-458d-a79d-1c7aff376d89",
+ "productFamilyId": "17cc1042-527b-11e6-beb8-9e71128cae77",
+ "subscriptionServiceType": "VIRTUAL USP",
+ "lcpCloudRegionId": "AAIAIC25",
+ "tenantId": "092eb9e8e4b7412e8787dd091bc58e86",
+ "aicZoneId": "DKJ1",
+ "projectName": "DFW",
+ "owningEntityId": "aaa1",
+ "instanceName": "Instance-Name",
+ "bulkSize": 1,
+ "modelInfo": {
+ "modelInvariantId": "e49fbd11-e60c-4a8e-b4bf-30fbe8f4fcc0",
+ "modelVersionId": "1a80c596-27e5-4ca9-b5bb-e03a7fd4c0fd",
+ "modelName": "action-data",
+ "modelVersion": "1.0"
+ },
+ "tenantName": "USP-SIP-IC-24335-T-01",
+ "aicZoneName": "DKJSJDKA-DKJ1",
+ "isUserProvidedNaming": true
+ }
+ }
+ ));
+ }
+
+ function generateFormGroup() {
+ return new FormGroup({
+ productFamilyId: new FormControl(),
+ lcpCloudRegionId: new FormControl(Validators.required),
+ tenantId: new FormControl({value: null, disabled: false}, Validators.required),
+ legacyRegion: new FormControl(),
+ lineOfBusiness: new FormControl(),
+ platformName: new FormControl(Validators.required),
+ rollbackOnFailure: new FormControl(Validators.required),
+ instanceName: new FormControl({value: null}, Validators.compose([Validators.required, NumbersLettersUnderscoreValidator.valid]))
+
+ });
+ }
+
+});
diff --git a/vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnf-instance-details.service.ts b/vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnf-instance-details.service.ts
new file mode 100644
index 000000000..677895e72
--- /dev/null
+++ b/vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnf-instance-details.service.ts
@@ -0,0 +1,64 @@
+import { Injectable } from '@angular/core';
+import { isNullOrUndefined } from "util";
+import { FormGroup } from '@angular/forms';
+@Injectable()
+export class VnfInstanceDetailsService {
+ isUnique(serviceInstance : any, serviceId : string, name: string, isEqualToOriginalInstanceName : boolean) : boolean {
+ const service = serviceInstance[serviceId];
+ let countInstanceName = 0;
+ let countVolumeGroupName = 0;
+ if(service){
+ if(service.instanceName === name) return false;
+ if(service.vnfs){
+ for(let key in service.vnfs){
+ if(service.vnfs[key].instanceName === name) {
+ countInstanceName++;
+ if((isEqualToOriginalInstanceName && countInstanceName > 1) || (!isEqualToOriginalInstanceName)) return false;
+ }
+ if(service.vnfs[key].vfModules){
+ for(let vfModule in service.vnfs[key].vfModules){
+ if(service.vnfs[key].vfModules[vfModule]) {
+ for(let module in service.vnfs[key].vfModules[vfModule]){
+ if(service.vnfs[key].vfModules[vfModule][module].instanceName === name ) {
+ countInstanceName++;
+ if((isEqualToOriginalInstanceName && countInstanceName > 1) || (!isEqualToOriginalInstanceName)) return false;
+ }
+
+ if(service.vnfs[key].vfModules[vfModule][module].volumeGroupName === name ) {
+ countVolumeGroupName++;
+ if((isEqualToOriginalInstanceName && countVolumeGroupName > 1) || (!isEqualToOriginalInstanceName)) return false;
+ }
+ }
+ }
+ }
+ }
+
+ }
+ }
+ }
+ return true;
+ }
+
+ hasApiError(controlName: string, data: Array<any>, form: FormGroup) {
+ if (!isNullOrUndefined(data)) {
+ if (!form.controls[controlName].disabled && data.length === 0) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ hasInstanceNameError(form : FormGroup) : boolean {
+ if(!isNullOrUndefined(form) && !isNullOrUndefined(form.controls['instanceName'])){
+ if (form.controls['instanceName'].touched && form.controls['instanceName'].errors && form.controls['instanceName'].errors.pattern) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ hasUniqueError(isNotUniqueInstanceName) : boolean {
+ return isNotUniqueInstanceName;
+ }
+
+}
diff --git a/vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnfPopupDataModel.ts b/vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnfPopupDataModel.ts
new file mode 100644
index 000000000..9a2694c70
--- /dev/null
+++ b/vid-webpack-master/src/app/components/vnf-popup/vnf-instance-details/vnfPopupDataModel.ts
@@ -0,0 +1,26 @@
+import {Project} from "../../../shared/models/project";
+import {LcpRegion} from "../../../shared/models/lcpRegion";
+import {Tenant} from "../../../shared/models/tenant";
+import {ProductFamily} from "../../../shared/models/productFamily";
+import {SelectOption, SelectOptionInterface} from "../../../shared/models/selectOption";
+
+export class VNFPopupDataModel {
+ productFamilies: ProductFamily[];
+ lcpRegions: LcpRegion[];
+ lcpRegionsTenantsMap: any;
+ tenants: Tenant[];
+ projects: Project[];
+ lineOfBusinesses: SelectOption[];
+ platforms: SelectOptionInterface[];
+ globalCustomerId: string;
+
+
+ constructor(){
+ this.lcpRegions = [];
+ this.lcpRegionsTenantsMap = {};
+ this.tenants = [];
+ this.productFamilies = [];
+ this.lineOfBusinesses = [];
+ this.platforms = [];
+ }
+}
diff --git a/vid-webpack-master/src/app/components/vnf-popup/vnf-popup-service.ts b/vid-webpack-master/src/app/components/vnf-popup/vnf-popup-service.ts
new file mode 100644
index 000000000..7dbe9b11b
--- /dev/null
+++ b/vid-webpack-master/src/app/components/vnf-popup/vnf-popup-service.ts
@@ -0,0 +1,55 @@
+import {Injectable} from "@angular/core";
+import {ServiceNodeTypeToModelKeyMapper} from "../../shared/models/serviceNodeTypeToModelKeyMapper";
+import {ServiceNodeTypes} from "../../shared/models/ServiceNodeTypes";
+import {VfModule} from "../../shared/models/vfModule";
+import {ServicePlanningService} from "../../services/service-planning.service";
+import {VNFModel} from "../../shared/models/vnfModel";
+import * as _ from 'lodash';
+import {isNullOrUndefined} from "util";
+import {NumbersLettersUnderscoreValidator} from '../../shared/components/validators/numbersLettersUnderscore/numbersLettersUnderscore.validator';
+import {FormGroup} from '@angular/forms';
+import {VnfInstanceDetailsComponent} from './vnf-instance-details/vnf-instance-details.component';
+import {VnfInstanceDetailsService} from './vnf-instance-details/vnf-instance-details.service';
+
+@Injectable()
+export class VnfPopupService {
+
+ constructor(private _servicePlanningService : ServicePlanningService, private _vnfInstanceDetailsService : VnfInstanceDetailsService) {
+ }
+
+ public getModelFromResponse(result : any, modelType : string, modelName:string) {
+ let model = null;
+ let rawModel = _.get(result, [ServiceNodeTypeToModelKeyMapper[modelType], modelName]);
+ if (!rawModel) return;
+
+ if (modelType === ServiceNodeTypes.VFmodule) {
+ model = new VfModule(rawModel);
+ }
+ else {
+ model = new VNFModel(rawModel);
+ }
+ return model;
+ }
+
+ onControlError(servicePopupDataModel : VnfInstanceDetailsComponent, serviceInstanceDetailsFormGroup : FormGroup, isNotUniqueInstanceName : boolean, isNotUniqueVolumeGroupName : boolean) : boolean{
+ if(this._vnfInstanceDetailsService.hasUniqueError(isNotUniqueInstanceName) || isNotUniqueVolumeGroupName){
+ return true;
+ }
+ if(!isNullOrUndefined(serviceInstanceDetailsFormGroup.controls['instanceName']) && NumbersLettersUnderscoreValidator.valid(serviceInstanceDetailsFormGroup.controls['instanceName'].value) && serviceInstanceDetailsFormGroup.controls['instanceName'].value != null && serviceInstanceDetailsFormGroup.controls['instanceName'].value.length > 0){
+ return true;
+ }
+
+ const controlName : Array<string> = ['lcpCloudRegionId', 'tenantId', 'lineOfBusiness', 'platformName'];
+ const selectDataName : Array<string> = ['lcpRegions', 'tenants', 'lineOfBusinesses', 'platforms', 'projects'];
+
+ for(let i = 0 ; i < controlName.length ; i++){
+ if (!isNullOrUndefined(servicePopupDataModel.vnfPopupDataModel) && !isNullOrUndefined(servicePopupDataModel.vnfPopupDataModel[selectDataName[i]])) {
+ if (!isNullOrUndefined(serviceInstanceDetailsFormGroup.controls[controlName[i]]) && !serviceInstanceDetailsFormGroup.controls[controlName[i]].disabled && servicePopupDataModel.vnfPopupDataModel[selectDataName[i]].length === 0) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+}
diff --git a/vid-webpack-master/src/app/components/vnf-popup/vnf-popup.components.ts b/vid-webpack-master/src/app/components/vnf-popup/vnf-popup.components.ts
new file mode 100644
index 000000000..26e667d4c
--- /dev/null
+++ b/vid-webpack-master/src/app/components/vnf-popup/vnf-popup.components.ts
@@ -0,0 +1,190 @@
+import {Component, OnInit, ViewChild} from "@angular/core";
+import {AaiService} from "../../services/aaiService/aai.service";
+import {ModelInformationItem} from "../../shared/components/model-information/model-information.component";
+import {ActivatedRoute} from "@angular/router";
+import {DialogComponent, DialogService} from "ng2-bootstrap-modal";
+import {InstancePopup} from "../instance-popup/instance-popup.components";
+import {ServiceModel} from "../../shared/models/serviceModel";
+import {Constants} from "../../shared/utils/constants";
+import * as _ from "lodash";
+import {VnfInstance} from "../../shared/models/vnfInstance";
+import {ServiceInstance} from "../../shared/models/serviceInstance";
+import {VnfInstanceDetailsComponent} from "./vnf-instance-details/vnf-instance-details.component";
+import {Subscriber} from "../../shared/models/subscriber";
+import {ServiceNodeTypes} from "../../shared/models/ServiceNodeTypes";
+import {AppState} from "../../store/reducers";
+import {NgRedux} from "@angular-redux/store";
+import {VfModuleInstance} from "../../shared/models/vfModuleInstance";
+import {VnfPopupService} from './vnf-popup-service';
+import {IframeService} from "../../shared/utils/iframe.service";
+
+export interface VnfPopupModel {
+ serviceModelId: string;
+ modelName: string;
+ parentModelName: string;
+ modelType: string;
+ dynamicInputs: any;
+ userProvidedNaming: boolean;
+ isNewVfModule : boolean;
+}
+
+@Component({
+ selector: 'vnf-popup',
+ templateUrl: 'vnf-popup.html',
+ styleUrls: ['vnf-popup.scss'],
+ providers: [AaiService, VnfPopupService]
+})
+
+export class VnfPopupComponent extends DialogComponent<VnfPopupModel, boolean> implements VnfPopupModel, InstancePopup, OnInit {
+
+ @ViewChild(VnfInstanceDetailsComponent) vnfInstanceDetails: VnfInstanceDetailsComponent;
+
+ serviceModelId: string;
+ modelName: string;
+ parentModelName: string;
+ modelType: string;
+ isNewVfModule : boolean;
+ model: any;
+ serviceModel: ServiceModel;
+ popupTypeName: string;
+ serviceInstance: ServiceInstance;
+ vnfInstance: VnfInstance;
+ dynamicInputs;
+ userProvidedNaming: boolean;
+ typeMapperForTitle = {
+ VF: "VNF",
+ VFmodule: "Module (Heat stack)"
+ };
+
+ modelInformationItems: Array<ModelInformationItem> = [];
+ isNotUniqueInstanceName : boolean = false;
+ isNotUniqueVolumeGroupName : boolean = false;
+ hasGeneralApiError : boolean = false;
+
+ parentElementClassName = 'content';
+
+ constructor(dialogService: DialogService, protected route: ActivatedRoute, protected _aaiService: AaiService,
+ private store: NgRedux<AppState>,
+ private _iframeService : IframeService,
+ private _vnfPopupService: VnfPopupService) {
+ super(dialogService);
+ this.vnfInstance = new VnfInstance();
+ }
+
+ updateGeneralErrorSection() : void {
+ this.hasGeneralApiError = this._vnfPopupService.onControlError(
+ this.vnfInstanceDetails,
+ this.vnfInstanceDetails.instanceFormGroup,
+ this.vnfInstanceDetails.isNotUniqueInstanceName,
+ this.vnfInstanceDetails.isNotUniqueVolumeGroupName);
+ }
+
+ ngOnInit(): void {
+ this.updateServiceModelById();
+ this.popupTypeName = this.getModelTypeForPopupTitle();
+ this.updateServiceModelById();
+ this.updateInstanceFromStore();
+ }
+
+ onCancelClick() {
+ this._iframeService.removeClassCloseModal(this.parentElementClassName);
+ super.close();
+ }
+
+ onServiceInstanceNameChanged(isNotUniqueInstanceName: boolean) : void {
+ this.isNotUniqueInstanceName = isNotUniqueInstanceName;
+ }
+
+ onVolumeGroupNameChanged(isNotUniqueVolumeGroupName: boolean) : void {
+ this.isNotUniqueVolumeGroupName = isNotUniqueVolumeGroupName;
+ }
+
+ onSetClick() {
+ this._iframeService.removeClassCloseModal(this.parentElementClassName);
+ this.result = true;
+ super.close();
+ }
+
+ updateServiceModelById() {
+ this._aaiService.getServiceModelById(this.serviceModelId).subscribe(
+ result => {
+ this.serviceModel = new ServiceModel(result);
+ this.model = this._vnfPopupService.getModelFromResponse(result, this.modelType, this.modelName);
+ this.modelInformationItems = this.createModelInformationItems();
+ },
+ error => {
+ console.log('error is ', error)
+ }
+ );
+ }
+
+ updateInstanceFromStore() {
+ let instance;
+ const serviceInstance = this.store.getState().service.serviceInstance[this.serviceModelId];
+ if (this.modelType === ServiceNodeTypes.VF) {
+ instance = serviceInstance.vnfs[this.modelName] || new VnfInstance();
+ } else {
+ instance = new VfModuleInstance();
+ }
+
+ if (instance.instanceParams && instance.instanceParams[0]) {
+ this.dynamicInputs = this.dynamicInputs.map(x => {
+ x.value = (instance.instanceParams[0][x.id]) ? instance.instanceParams[0][x.id] : x.value;
+ return x;
+ });
+ }
+ this.vnfInstance = instance;
+ }
+
+ getModelName(): string {
+ return this.modelName;
+ }
+
+ getModelTypeForPopupTitle(): string {
+ if (_.has(this.typeMapperForTitle, this.modelType)) {
+ return this.typeMapperForTitle[this.modelType];
+ }
+ return this.modelType;
+ }
+
+ extractSubscriberNameBySubscriberId(subsriberId: string) {
+ var result: string = null;
+ var filteredArray: any = _.filter(this.store.getState().service.subscribers, function (o: Subscriber) {
+ return o.id === subsriberId
+ })
+ if (filteredArray.length > 0) {
+ result = filteredArray[0].name;
+ }
+ return result;
+ }
+
+ createModelInformationItems(): Array<ModelInformationItem> {
+ var serviceInstance = this.store.getState().service.serviceInstance[this.serviceModelId];
+
+ let items = [
+ new ModelInformationItem("Subscriber Name", "subscriberName", [this.extractSubscriberNameBySubscriberId(serviceInstance.globalSubscriberId)], "", true),
+ new ModelInformationItem("Service Name", "serviceModelName", [this.serviceModel.name], "", true),
+
+ new ModelInformationItem("Service Instance Name", "serviceName", [serviceInstance.instanceName], "", false),
+ new ModelInformationItem("Model Name", "modelName", [this.model.name], "", true),
+ new ModelInformationItem("Model version", "modelVersion", [this.model.version], "", true),
+ new ModelInformationItem("Description", "description", [this.model.description]),
+ new ModelInformationItem("Category", "category", [this.model.category]),
+ new ModelInformationItem("Sub Category", "subCategory",[this.model.subCategory]),
+ new ModelInformationItem("UUID", "uuid", [this.model.uuid], Constants.ServicePopup.TOOLTIP_UUID, true),
+ new ModelInformationItem("Invariant UUID", "invariantUuid", [this.model.invariantUuid], Constants.ServicePopup.TOOLTIP_INVARIANT_UUID, true),
+ new ModelInformationItem("Service type", "serviceType", [this.serviceModel.serviceType]),
+ new ModelInformationItem("Service role", "serviceRole", [this.serviceModel.serviceRole]),
+
+
+ ];
+ if (this.modelType === 'VFmodule') {
+ items.push(new ModelInformationItem("Minimum to instantiate", "min", [this.model.min], "", true),
+ new ModelInformationItem("Maximum to instantiate", "max", this.model.max == undefined ? [1] : [this.model.max], "", true),
+ new ModelInformationItem("Recommended to instantiate", "initial", [this.model.initial]));
+
+ }
+
+ return items;
+ }
+}
diff --git a/vid-webpack-master/src/app/components/vnf-popup/vnf-popup.html b/vid-webpack-master/src/app/components/vnf-popup/vnf-popup.html
new file mode 100644
index 000000000..d2e043b18
--- /dev/null
+++ b/vid-webpack-master/src/app/components/vnf-popup/vnf-popup.html
@@ -0,0 +1,54 @@
+<div id="instance-popup" class="modal-dialog">
+ <div class="modal-content">
+ <div class="modal-header">
+ <button type="button" class="close" (click)="onCancelClick()" >&times;</button>
+ <span [attr.data-tests-id]="'create-modal-title'" class="modal-title">Set a new {{popupTypeName}}</span>
+ </div>
+ <div class="modal-body popup-content">
+
+ <div class="header-left">
+ <div>MODEL: <span>"{{popupTypeName}}"</span></div>
+ </div>
+
+ <div class="header-right">
+ {{getModelTypeForPopupTitle()}} Instance Details
+ </div>
+
+ <div class="model-information">
+ <model-information [modelInformationItems]="modelInformationItems"></model-information>
+ </div>
+
+ <div class="instance-form">
+ <vnf-instance-details [dynamicInputs]="dynamicInputs"
+ [vnfModel]="model"
+ [modelType]="modelType"
+ [modelName]="modelName"
+ [parentModelName]="parentModelName"
+ [isNewVfModule]="isNewVfModule"
+ [serviceInstance]="vnfInstance"
+ [vnfInstance]="vnfInstance"
+ [serviceUuid]="serviceModelId"
+ [userProvidedNaming]="userProvidedNaming"
+ (onSubmitClick)="onSetClick($event)"
+ (onDataChanged)="updateGeneralErrorSection()"
+ (onServiceInstanceNameChanged)="onServiceInstanceNameChanged($event)"
+ (onVolumeGroupNameChanged)="onVolumeGroupNameChanged($event)"
+
+ ></vnf-instance-details>
+ </div>
+
+ </div>
+ <div class="modal-footer row" style="padding: 0">
+ <div class="col-md-6">
+ <div *ngIf="hasGeneralApiError == true">
+ <form-general-error [message]="'Page contains errors. Please see details next to the relevant fields.'"></form-general-error>
+ </div>
+ </div>
+ <div class="col-md-6" style="padding: 15px;padding-right: 35px;">
+ <button [attr.data-tests-id]="'cancelButton'" type="button" class="btn btn-default cancel" (click)="onCancelClick()"><span>Cancel</span></button>
+ <input type="submit" value="Set" form="vnfForm" data-tests-id="vnf-form-set"
+ class="btn btn-success submit" [disabled]="!vnfInstanceDetails?.vnfForm?.valid || isNotUniqueInstanceName || isNotUniqueVolumeGroupName">
+ </div>
+ </div>
+ </div>
+</div>
diff --git a/vid-webpack-master/src/app/components/vnf-popup/vnf-popup.scss b/vid-webpack-master/src/app/components/vnf-popup/vnf-popup.scss
new file mode 100644
index 000000000..6e606dbb9
--- /dev/null
+++ b/vid-webpack-master/src/app/components/vnf-popup/vnf-popup.scss
@@ -0,0 +1,185 @@
+$grid-border: 1px #d2d2d2 solid;
+
+#instance-popup {
+ color: #191919;
+
+ .left-panel {
+ background: #f2f2f2;
+ border-right: $grid-border;
+ }
+
+ .header-common {
+ height: 100%;
+ align-items: center;
+ display: flex;
+ font-family: OpenSans-Semibold;
+ font-size: 12px;
+ }
+
+ .header-text {
+ padding-left: 30px;
+ @extend .header-common;
+ }
+
+ .header-left {
+ grid-area: header-left;
+ @extend .header-text;
+ @extend .left-panel;
+ border-bottom: $grid-border;
+
+ span {
+ font-family: OpenSans-Regular;
+ font-size: 14px;
+ };
+ }
+
+ .header-right {
+ grid-area: header-right;
+
+ @extend .header-text;
+ border-bottom: $grid-border;
+ }
+
+ .quantity-label {
+ grid-area: quantity-label;
+ @extend .header-common;
+ border-bottom: $grid-border;
+ height: 100%;
+ font-family: OpenSans-Regular;
+ }
+
+ .quantity {
+ grid-area: quantity;
+ border-left: $grid-border;
+ border-bottom: $grid-border;
+ border-top-style: none;
+ font-family: OpenSans-Semibold;
+ text-align: start;
+ text-indent: 10px;
+ }
+
+ .quantity-select {
+ width: 78px;
+ height: 100%;
+ border: 0;
+ background: white;
+ outline: none;
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ appearance: none;
+ background: url('../../../assets/img/chevron.svg') 0 0 no-repeat;
+ background-size: 24px;
+ background-position-x: right;
+ background-position-y: center;
+ }
+ input[type="number"]:hover::-webkit-inner-spin-button {
+ height: 20px;
+ }
+
+ .model-information {
+ grid-area: model-information;
+
+ padding: 30px;
+ overflow: auto;
+ @extend .left-panel;
+ }
+
+ .instance-form {
+ grid-area: instance-form;
+ }
+
+ .popup-content {
+ display: grid;
+ grid-template-columns: 400px auto 30px 93px;
+ grid-template-rows: 50px calc(100vh - 180px);
+ grid-template-areas:
+ "header-left header-right header-right header-right"
+ "model-information instance-form instance-form instance-form";
+ padding: 0;
+ }
+}
+
+.modal {
+ background-color: #191919;
+ opacity: 0.8;
+}
+
+.modal-dialog {
+ position: relative;
+ width: auto;
+ margin: 0;
+}
+@media (min-width: 1150px) {
+ .popup-content {
+ grid-template-rows: 30px 680px;
+ }
+}
+
+.modal-content {
+ border-radius: 0;
+ box-shadow: none;
+ border: none;
+}
+
+.modal-footer {
+ .cancel {
+ width: 120px;
+ height: 36px;
+ background: #ffffff;
+ border: 1px solid #009fdb;
+ border-radius: 2px;
+ span {
+ font-family: OpenSans-Regular;
+ font-size: 14px;
+ color: #009fdb;
+ line-height: 16px;
+ }
+ }
+
+ .submit {
+ width: 120px;
+ height: 36px;
+ background: #009fdb;
+ border-radius: 2px;
+ border-color: #009fdb;
+ span {
+ font-family: OpenSans-Regular;
+ font-size: 14px;
+ color: #FFFFFF;
+ line-height: 16px;
+ }
+ }
+}
+
+.modal-header {
+ background-color: #009fdb;
+
+ padding-bottom: 13px;
+ padding-top: 13px;
+ padding-left: 29px;
+ padding-right: 21px;
+
+ .close {
+ font-size: 32px;
+ font-weight: 200;
+ color: #d8d8d8;
+ text-shadow: none;
+ filter: none;
+ opacity: 1;
+ }
+
+ .modal-title {
+ font-family: OpenSans-Regular;
+ font-size: 24px;
+ color: #fff;
+ line-height: 34px;
+ }
+}
+//
+//@media (min-width: 1200px) {
+// .service-model,
+// .service-instance {
+// width: 1050px;
+// margin: 30px auto;
+// }
+//}
diff --git a/vid-webpack-master/src/app/components/vnf-popup/vnf-popup.service.spec.ts b/vid-webpack-master/src/app/components/vnf-popup/vnf-popup.service.spec.ts
new file mode 100644
index 000000000..02296f728
--- /dev/null
+++ b/vid-webpack-master/src/app/components/vnf-popup/vnf-popup.service.spec.ts
@@ -0,0 +1,827 @@
+import {VnfPopupService} from './vnf-popup-service';
+import {ServicePlanningService} from '../../services/service-planning.service';
+import {ServiceNodeTypes} from '../../shared/models/ServiceNodeTypes';
+import {NgRedux} from '@angular-redux/store';
+import {VNFModel} from '../../shared/models/vnfModel';
+import {VfModule} from '../../shared/models/vfModule';
+import {FormControl, FormGroup, Validators} from '@angular/forms';
+import {NumbersLettersUnderscoreValidator} from '../../shared/components/validators/numbersLettersUnderscore/numbersLettersUnderscore.validator';
+import {VnfInstanceDetailsService} from './vnf-instance-details/vnf-instance-details.service';
+import {ReflectiveInjector} from '@angular/core';
+
+export class MockAppStore<T> {
+}
+
+describe('Vnf popup service', () => {
+ let injector;
+ let service: VnfPopupService;
+ let fg: FormGroup;
+ let data = generateModelData();
+ let servicePopupDataModel = generateServicePopupDataModel();
+ let form: FormGroup = generateFormGroup();
+ beforeEach(() => {
+
+ let injector = ReflectiveInjector.resolveAndCreate([
+ VnfPopupService,
+ ServicePlanningService,
+ VnfInstanceDetailsService,
+ {provide: FormGroup, useClass: MockAppStore},
+ {provide: NgRedux, useClass: MockAppStore}
+ ]);
+
+ service = injector.get(VnfPopupService);
+ fg = injector.get(FormGroup);
+ });
+
+ describe('#updateVnfDataFromModel', () => {
+ it('update vnf data from model should return new vnf', (done: DoneFn) => {
+ let vnf: VNFModel = service.getModelFromResponse(data, ServiceNodeTypes.VF, '2017-388_ADIOD-vPE 1');
+
+ expect(vnf).toEqual(jasmine.any(VNFModel));
+ done();
+ });
+
+ it('update wrong vnf data from model should be undefined', (done: DoneFn) => {
+ let vnf: VNFModel = service.getModelFromResponse(data, ServiceNodeTypes.VF, '2017-388_ADIOD-vPE 3');
+
+ expect(vnf).toBeUndefined();
+ done();
+ });
+
+ it('update vfModule data from model should return new vfModule', (done: DoneFn) => {
+ let vfModule: VfModule = service.getModelFromResponse(data, ServiceNodeTypes.VFmodule, '2017488_adiodvpe0..2017488AdiodVpe..ADIOD_vRE_BV..module-1');
+
+ expect(vfModule).toEqual(jasmine.any(VfModule));
+ done();
+ });
+
+ });
+
+
+ describe('#onControlError', () => {
+ it('onControlError should return true if instanceName is not legal', (done: DoneFn) => {
+ form.controls['instanceName'].setValue('aaaa - aaa');
+
+ let result: boolean = service.onControlError(<any>servicePopupDataModel, form, false, false);
+ expect(result).toBeTruthy();
+ done();
+ });
+
+ it('onControlError should return false if instanceName is legal', (done: DoneFn) => {
+
+ form.controls['instanceName'].setValue('aaaa');
+ let result = service.onControlError(<any>servicePopupDataModel, form, false, false);
+ expect(result).toBeFalsy();
+ done();
+ });
+
+ it('onControlError should return true if instanceName is not unique', (done: DoneFn) => {
+
+ form.controls['instanceName'].setValue('aaaa');
+ let result = service.onControlError(<any>servicePopupDataModel, form, true, false);
+ expect(result).toBeTruthy();
+ done();
+ });
+
+ it('onControlError should return true if lcpRegions is empty', (done: DoneFn) => {
+ servicePopupDataModel.vnfPopupDataModel['lcpRegions'] = [];
+ let result = service.onControlError(<any>servicePopupDataModel, form, true, false);
+ expect(result).toBeTruthy();
+ done();
+ });
+
+ it('onControlError should return true if isNotUniqueVolumeGroupName is true', (done: DoneFn) => {
+ let result = service.onControlError(<any>servicePopupDataModel, form, true, true);
+ expect(result).toBeTruthy();
+ done();
+ })
+ });
+
+
+ function generateServicePopupDataModel() {
+ return {
+ 'vnfPopupDataModel': JSON.parse('{"tenants" : [1,2,3],"lcpRegions":[1,2,3],"lcpRegionsTenantsMap":{},"productFamilies":[1,2,3],"lineOfBusinesses":[{"id":"ECOMP","name":"ECOMP"},{"id":"zzz1","name":"zzz1"}],"platforms":[{"id":"platform","name":"platform"},{"id":"xxx1","name":"xxx1"}],"rollbackOnFailure":[{"id":"true","name":"Rollback"}]}')
+ }
+ }
+
+ function generateFormGroup() {
+ return new FormGroup({
+ productFamilyId: new FormControl(),
+ lcpCloudRegionId: new FormControl(Validators.required),
+ tenantId: new FormControl({value: null, disabled: false}, Validators.required),
+ legacyRegion: new FormControl(),
+ lineOfBusiness: new FormControl(),
+ platformName: new FormControl(Validators.required),
+ instanceName: new FormControl({value: null}, Validators.compose([Validators.required, NumbersLettersUnderscoreValidator.valid]))
+ });
+ }
+
+ function generateModelData() {
+ return JSON.parse(JSON.stringify(
+ {
+ 'service': {
+ 'uuid': '2f80c596-27e5-4ca9-b5bb-e03a7fd4c0fd',
+ 'invariantUuid': 'e49fbd11-e60c-4a8e-b4bf-30fbe8f4fcc0',
+ 'name': 'action-data',
+ 'version': '1.0',
+ 'toscaModelURL': null,
+ 'category': '',
+ 'serviceType': '',
+ 'serviceRole': '',
+ 'description': '',
+ 'serviceEcompNaming': 'true',
+ 'instantiationType': 'ClientConfig',
+ 'inputs': {
+ '2017488_adiodvpe0_ASN': {
+ 'type': 'string',
+ 'description': 'AV/PE',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': 'AV_vPE'
+ },
+ 'adiodvpe0_bandwidth': {
+ 'type': 'string',
+ 'description': 'Requested VPE bandwidth',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': '10'
+ },
+ '2017488_adiodvpe0_vnf_instance_name': {
+ 'type': 'string',
+ 'description': 'The hostname assigned to the vpe.',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': 'mtnj309me6'
+ },
+ '2017488_adiodvpe0_vnf_config_template_version': {
+ 'type': 'string',
+ 'description': 'VPE Software Version',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': '17.2'
+ },
+ '2017488_adiodvpe0_AIC_CLLI': {
+ 'type': 'string',
+ 'description': 'AIC Site CLLI',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': 'ATLMY8GA'
+ },
+ 'adiodvpe0_bandwidth_units': {
+ 'type': 'string',
+ 'description': 'Units of bandwidth',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': 'Gbps'
+ }
+ }
+ },
+ 'vnfs': {
+ '2017-388_ADIOD-vPE 1': {
+ 'uuid': '0903e1c0-8e03-4936-b5c2-260653b96413',
+ 'invariantUuid': '00beb8f9-6d39-452f-816d-c709b9cbb87d',
+ 'description': 'Name ADIOD vPE Description The provider edge function for the ADIOD service supported by the Junipers VMX product Category Router Vendor Juniper Vendor Release Code 17.2 Owners Mary Fragale. Updated 9-25 to use v8.0 of the Juniper Valid 2 VLM',
+ 'name': '2017-388_ADIOD-vPE',
+ 'version': '1.0',
+ 'customizationUuid': '280dec31-f16d-488b-9668-4aae55d6648a',
+ 'inputs': {
+ 'vnf_config_template_version': {
+ 'type': 'string',
+ 'description': 'VPE Software Version',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': '17.2'
+ },
+ 'bandwidth_units': {
+ 'type': 'string',
+ 'description': 'Units of bandwidth',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': 'Gbps'
+ },
+ 'bandwidth': {
+ 'type': 'string',
+ 'description': 'Requested VPE bandwidth',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': '10'
+ },
+ 'AIC_CLLI': {
+ 'type': 'string',
+ 'description': 'AIC Site CLLI',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': 'ATLMY8GA'
+ },
+ 'ASN': {
+ 'type': 'string',
+ 'description': 'AV/PE',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': 'AV_vPE'
+ },
+ 'vnf_instance_name': {
+ 'type': 'string',
+ 'description': 'The hostname assigned to the vpe.',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': 'mtnj309me6'
+ }
+ },
+ 'commands': {
+ 'vnf_config_template_version': {
+ 'displayName': 'vnf_config_template_version',
+ 'command': 'get_input',
+ 'inputName': '2017488_adiodvpe0_vnf_config_template_version'
+ },
+ 'bandwidth_units': {
+ 'displayName': 'bandwidth_units',
+ 'command': 'get_input',
+ 'inputName': 'adiodvpe0_bandwidth_units'
+ },
+ 'bandwidth': {'displayName': 'bandwidth', 'command': 'get_input', 'inputName': 'adiodvpe0_bandwidth'},
+ 'AIC_CLLI': {'displayName': 'AIC_CLLI', 'command': 'get_input', 'inputName': '2017488_adiodvpe0_AIC_CLLI'},
+ 'ASN': {'displayName': 'ASN', 'command': 'get_input', 'inputName': '2017488_adiodvpe0_ASN'},
+ 'vnf_instance_name': {
+ 'displayName': 'vnf_instance_name',
+ 'command': 'get_input',
+ 'inputName': '2017488_adiodvpe0_vnf_instance_name'
+ }
+ },
+ 'properties': {
+ 'vmxvre_retype': 'RE-VMX',
+ 'vnf_config_template_version': 'get_input:2017488_adiodvpe0_vnf_config_template_version',
+ 'sriov44_net_id': '48d399b3-11ee-48a8-94d2-f0ea94d6be8d',
+ 'int_ctl_net_id': '2f323477-6936-4d01-ac53-d849430281d9',
+ 'vmxvpfe_sriov41_0_port_mac': '00:11:22:EF:AC:DF',
+ 'int_ctl_net_name': 'VMX-INTXI',
+ 'vmx_int_ctl_prefix': '128.0.0.0',
+ 'sriov43_net_id': 'da349ca1-6de9-4548-be88-2d88e99bfef5',
+ 'sriov42_net_id': '760669ba-013d-4d9b-b0e7-4151fe2e6279',
+ 'sriov41_net_id': '25ad52d5-c165-40f8-b3b0-ddfc2373280a',
+ 'nf_type': 'vPE',
+ 'vmxvpfe_int_ctl_ip_1': '128.0.0.16',
+ 'is_AVPN_service': 'false',
+ 'vmx_RSG_name': 'vREXI-affinity',
+ 'vmx_int_ctl_forwarding': 'l2',
+ 'vmxvre_oam_ip_0': '10.40.123.5',
+ 'vmxvpfe_sriov44_0_port_mac': '00:11:22:EF:AC:DF',
+ 'vmxvpfe_sriov41_0_port_vlanstrip': 'false',
+ 'vmxvpfe_sriov42_0_port_vlanfilter': '4001',
+ 'vmxvpfe_sriov44_0_port_unknownunicastallow': 'true',
+ 'vmxvre_image_name_0': 'VRE-ENGINE_17.2-S2.1.qcow2',
+ 'vmxvre_instance': '0',
+ 'vmxvpfe_sriov43_0_port_mac': '00:11:22:EF:AC:DF',
+ 'vmxvre_flavor_name': 'ns.c1r16d32.v5',
+ 'vmxvpfe_volume_size_0': '40.0',
+ 'vmxvpfe_sriov43_0_port_vlanfilter': '4001',
+ 'nf_naming': '{ecomp_generated_naming=true}',
+ 'nf_naming_code': 'Navneet',
+ 'vmxvre_name_0': 'vREXI',
+ 'vmxvpfe_sriov42_0_port_vlanstrip': 'false',
+ 'vmxvpfe_volume_name_0': 'vPFEXI_FBVolume',
+ 'vmx_RSG_id': 'bd89a33c-13c3-4a04-8fde-1a57eb123141',
+ 'vmxvpfe_image_name_0': 'VPE_ROUTING-ENGINE_17.2R1-S2.1.qcow2',
+ 'vmxvpfe_sriov43_0_port_unknownunicastallow': 'true',
+ 'vmxvpfe_sriov44_0_port_unknownmulticastallow': 'true',
+ 'vmxvre_console': 'vidconsole',
+ 'vmxvpfe_sriov44_0_port_vlanfilter': '4001',
+ 'vmxvpfe_sriov42_0_port_mac': '00:11:22:EF:AC:DF',
+ 'vmxvpfe_volume_id_0': '47cede15-da2f-4397-a101-aa683220aff3',
+ 'vmxvpfe_sriov42_0_port_unknownmulticastallow': 'true',
+ 'vmxvpfe_sriov44_0_port_vlanstrip': 'false',
+ 'vf_module_id': '123',
+ 'nf_function': 'JAI',
+ 'vmxvpfe_sriov43_0_port_unknownmulticastallow': 'true',
+ 'vmxvre_int_ctl_ip_0': '128.0.0.1',
+ 'AIC_CLLI': 'get_input:2017488_adiodvpe0_AIC_CLLI',
+ 'vnf_name': 'mtnj309me6vre',
+ 'vmxvpfe_sriov41_0_port_unknownunicastallow': 'true',
+ 'vmxvre_volume_type_1': 'HITACHI',
+ 'vmxvpfe_sriov44_0_port_broadcastallow': 'true',
+ 'vmxvre_volume_type_0': 'HITACHI',
+ 'vmxvpfe_volume_type_0': 'HITACHI',
+ 'vmxvpfe_sriov43_0_port_broadcastallow': 'true',
+ 'bandwidth_units': 'get_input:adiodvpe0_bandwidth_units',
+ 'vnf_id': '123',
+ 'vmxvre_oam_prefix': '24',
+ 'availability_zone_0': 'mtpocfo-kvm-az01',
+ 'ASN': 'get_input:2017488_adiodvpe0_ASN',
+ 'vmxvre_chassis_i2cid': '161',
+ 'vmxvpfe_name_0': 'vPFEXI',
+ 'bandwidth': 'get_input:adiodvpe0_bandwidth',
+ 'availability_zone_max_count': '1',
+ 'vmxvre_volume_size_0': '45.0',
+ 'vmxvre_volume_size_1': '50.0',
+ 'vmxvpfe_sriov42_0_port_broadcastallow': 'true',
+ 'vmxvre_oam_gateway': '10.40.123.1',
+ 'vmxvre_volume_name_1': 'vREXI_FAVolume',
+ 'vmxvre_ore_present': '0',
+ 'vmxvre_volume_name_0': 'vREXI_FBVolume',
+ 'vmxvre_type': '0',
+ 'vnf_instance_name': 'get_input:2017488_adiodvpe0_vnf_instance_name',
+ 'vmxvpfe_sriov41_0_port_unknownmulticastallow': 'true',
+ 'oam_net_id': 'b95eeb1d-d55d-4827-abb4-8ebb94941429',
+ 'vmx_int_ctl_len': '24',
+ 'vmxvpfe_sriov43_0_port_vlanstrip': 'false',
+ 'vmxvpfe_sriov41_0_port_broadcastallow': 'true',
+ 'vmxvre_volume_id_1': '6e86797e-03cd-4fdc-ba72-2957119c746d',
+ 'vmxvpfe_sriov41_0_port_vlanfilter': '4001',
+ 'nf_role': 'Testing',
+ 'vmxvre_volume_id_0': 'f4eacb79-f687-4e9d-b760-21847c8bb15a',
+ 'vmxvpfe_sriov42_0_port_unknownunicastallow': 'true',
+ 'vmxvpfe_flavor_name': 'ns.c20r16d25.v5'
+ },
+ 'type': 'VF',
+ 'modelCustomizationName': '2017-388_ADIOD-vPE 1',
+ 'vfModules': {},
+ 'volumeGroups': {}
+ },
+ '2017-388_ADIOD-vPE 0': {
+ 'uuid': 'afacccf6-397d-45d6-b5ae-94c39734b168',
+ 'invariantUuid': '72e465fe-71b1-4e7b-b5ed-9496118ff7a8',
+ 'description': 'Name ADIOD vPE Description The provider edge function for the ADIOD service supported by the Junipers VMX product Category Router Vendor Juniper Vendor Release Code 17.2 Owners Mary Fragale. Updated 9-25 to use v8.0 of the Juniper Valid 2 VLM',
+ 'name': '2017-388_ADIOD-vPE',
+ 'version': '4.0',
+ 'customizationUuid': 'b3c76f73-eeb5-4fb6-9d31-72a889f1811c',
+ 'inputs': {
+ 'vnf_config_template_version': {
+ 'type': 'string',
+ 'description': 'VPE Software Version',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': '17.2'
+ },
+ 'bandwidth_units': {
+ 'type': 'string',
+ 'description': 'Units of bandwidth',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': 'Gbps'
+ },
+ 'bandwidth': {
+ 'type': 'string',
+ 'description': 'Requested VPE bandwidth',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': '10'
+ },
+ 'AIC_CLLI': {
+ 'type': 'string',
+ 'description': 'AIC Site CLLI',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': 'ATLMY8GA'
+ },
+ 'ASN': {
+ 'type': 'string',
+ 'description': 'AV/PE',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': 'AV_vPE'
+ },
+ 'vnf_instance_name': {
+ 'type': 'string',
+ 'description': 'The hostname assigned to the vpe.',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': 'mtnj309me6'
+ }
+ },
+ 'commands': {
+ 'vnf_config_template_version': {
+ 'displayName': 'vnf_config_template_version',
+ 'command': 'get_input',
+ 'inputName': '2017488_adiodvpe0_vnf_config_template_version'
+ },
+ 'bandwidth_units': {
+ 'displayName': 'bandwidth_units',
+ 'command': 'get_input',
+ 'inputName': 'adiodvpe0_bandwidth_units'
+ },
+ 'bandwidth': {'displayName': 'bandwidth', 'command': 'get_input', 'inputName': 'adiodvpe0_bandwidth'},
+ 'AIC_CLLI': {'displayName': 'AIC_CLLI', 'command': 'get_input', 'inputName': '2017488_adiodvpe0_AIC_CLLI'},
+ 'ASN': {'displayName': 'ASN', 'command': 'get_input', 'inputName': '2017488_adiodvpe0_ASN'},
+ 'vnf_instance_name': {
+ 'displayName': 'vnf_instance_name',
+ 'command': 'get_input',
+ 'inputName': '2017488_adiodvpe0_vnf_instance_name'
+ }
+ },
+ 'properties': {
+ 'vmxvre_retype': 'RE-VMX',
+ 'vnf_config_template_version': 'get_input:2017488_adiodvpe0_vnf_config_template_version',
+ 'sriov44_net_id': '48d399b3-11ee-48a8-94d2-f0ea94d6be8d',
+ 'int_ctl_net_id': '2f323477-6936-4d01-ac53-d849430281d9',
+ 'vmxvpfe_sriov41_0_port_mac': '00:11:22:EF:AC:DF',
+ 'int_ctl_net_name': 'VMX-INTXI',
+ 'vmx_int_ctl_prefix': '128.0.0.0',
+ 'sriov43_net_id': 'da349ca1-6de9-4548-be88-2d88e99bfef5',
+ 'sriov42_net_id': '760669ba-013d-4d9b-b0e7-4151fe2e6279',
+ 'sriov41_net_id': '25ad52d5-c165-40f8-b3b0-ddfc2373280a',
+ 'nf_type': 'vPE',
+ 'vmxvpfe_int_ctl_ip_1': '128.0.0.16',
+ 'is_AVPN_service': 'false',
+ 'vmx_RSG_name': 'vREXI-affinity',
+ 'vmx_int_ctl_forwarding': 'l2',
+ 'vmxvre_oam_ip_0': '10.40.123.5',
+ 'vmxvpfe_sriov44_0_port_mac': '00:11:22:EF:AC:DF',
+ 'vmxvpfe_sriov41_0_port_vlanstrip': 'false',
+ 'vmxvpfe_sriov42_0_port_vlanfilter': '4001',
+ 'vmxvpfe_sriov44_0_port_unknownunicastallow': 'true',
+ 'vmxvre_image_name_0': 'VRE-ENGINE_17.2-S2.1.qcow2',
+ 'vmxvre_instance': '0',
+ 'vmxvpfe_sriov43_0_port_mac': '00:11:22:EF:AC:DF',
+ 'vmxvre_flavor_name': 'ns.c1r16d32.v5',
+ 'vmxvpfe_volume_size_0': '40.0',
+ 'vmxvpfe_sriov43_0_port_vlanfilter': '4001',
+ 'nf_naming': '{ecomp_generated_naming=true}',
+ 'nf_naming_code': 'Navneet',
+ 'vmxvre_name_0': 'vREXI',
+ 'vmxvpfe_sriov42_0_port_vlanstrip': 'false',
+ 'vmxvpfe_volume_name_0': 'vPFEXI_FBVolume',
+ 'vmx_RSG_id': 'bd89a33c-13c3-4a04-8fde-1a57eb123141',
+ 'vmxvpfe_image_name_0': 'VPE_ROUTING-ENGINE_17.2R1-S2.1.qcow2',
+ 'vmxvpfe_sriov43_0_port_unknownunicastallow': 'true',
+ 'vmxvpfe_sriov44_0_port_unknownmulticastallow': 'true',
+ 'vmxvre_console': 'vidconsole',
+ 'vmxvpfe_sriov44_0_port_vlanfilter': '4001',
+ 'vmxvpfe_sriov42_0_port_mac': '00:11:22:EF:AC:DF',
+ 'vmxvpfe_volume_id_0': '47cede15-da2f-4397-a101-aa683220aff3',
+ 'vmxvpfe_sriov42_0_port_unknownmulticastallow': 'true',
+ 'vmxvpfe_sriov44_0_port_vlanstrip': 'false',
+ 'vf_module_id': '123',
+ 'nf_function': 'JAI',
+ 'vmxvpfe_sriov43_0_port_unknownmulticastallow': 'true',
+ 'vmxvre_int_ctl_ip_0': '128.0.0.1',
+ 'AIC_CLLI': 'get_input:2017488_adiodvpe0_AIC_CLLI',
+ 'vnf_name': 'mtnj309me6vre',
+ 'vmxvpfe_sriov41_0_port_unknownunicastallow': 'true',
+ 'vmxvre_volume_type_1': 'HITACHI',
+ 'vmxvpfe_sriov44_0_port_broadcastallow': 'true',
+ 'vmxvre_volume_type_0': 'HITACHI',
+ 'vmxvpfe_volume_type_0': 'HITACHI',
+ 'vmxvpfe_sriov43_0_port_broadcastallow': 'true',
+ 'bandwidth_units': 'get_input:adiodvpe0_bandwidth_units',
+ 'vnf_id': '123',
+ 'vmxvre_oam_prefix': '24',
+ 'availability_zone_0': 'mtpocfo-kvm-az01',
+ 'ASN': 'get_input:2017488_adiodvpe0_ASN',
+ 'vmxvre_chassis_i2cid': '161',
+ 'vmxvpfe_name_0': 'vPFEXI',
+ 'bandwidth': 'get_input:adiodvpe0_bandwidth',
+ 'availability_zone_max_count': '1',
+ 'vmxvre_volume_size_0': '45.0',
+ 'vmxvre_volume_size_1': '50.0',
+ 'vmxvpfe_sriov42_0_port_broadcastallow': 'true',
+ 'vmxvre_oam_gateway': '10.40.123.1',
+ 'vmxvre_volume_name_1': 'vREXI_FAVolume',
+ 'vmxvre_ore_present': '0',
+ 'vmxvre_volume_name_0': 'vREXI_FBVolume',
+ 'vmxvre_type': '0',
+ 'vnf_instance_name': 'get_input:2017488_adiodvpe0_vnf_instance_name',
+ 'vmxvpfe_sriov41_0_port_unknownmulticastallow': 'true',
+ 'oam_net_id': 'b95eeb1d-d55d-4827-abb4-8ebb94941429',
+ 'vmx_int_ctl_len': '24',
+ 'vmxvpfe_sriov43_0_port_vlanstrip': 'false',
+ 'vmxvpfe_sriov41_0_port_broadcastallow': 'true',
+ 'vmxvre_volume_id_1': '6e86797e-03cd-4fdc-ba72-2957119c746d',
+ 'vmxvpfe_sriov41_0_port_vlanfilter': '4001',
+ 'nf_role': 'Testing',
+ 'vmxvre_volume_id_0': 'f4eacb79-f687-4e9d-b760-21847c8bb15a',
+ 'vmxvpfe_sriov42_0_port_unknownunicastallow': 'true',
+ 'vmxvpfe_flavor_name': 'ns.c20r16d25.v5'
+ },
+ 'type': 'VF',
+ 'modelCustomizationName': '2017-388_ADIOD-vPE 0',
+ 'vfModules': {},
+ 'volumeGroups': {}
+ },
+ '2017488_ADIODvPE 0': {
+ 'uuid': '69e09f68-8b63-4cc9-b9ff-860960b5db09',
+ 'invariantUuid': '72e465fe-71b1-4e7b-b5ed-9496118ff7a8',
+ 'description': 'Name ADIOD vPE Description The provider edge function for the ADIOD service supported by the Junipers VMX product Category Router Vendor Juniper Vendor Release Code 17.2 Owners Mary Fragale. Updated 9-25 to use v8.0 of the Juniper Valid 2 VLM',
+ 'name': '2017488_ADIODvPE',
+ 'version': '5.0',
+ 'customizationUuid': '1da7b585-5e61-4993-b95e-8e6606c81e45',
+ 'inputs': {
+ 'vnf_config_template_version': {
+ 'type': 'string',
+ 'description': 'VPE Software Version',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': '17.2'
+ },
+ 'bandwidth_units': {
+ 'type': 'string',
+ 'description': 'Units of bandwidth',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': 'Gbps'
+ },
+ 'bandwidth': {
+ 'type': 'string',
+ 'description': 'Requested VPE bandwidth',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': '10'
+ },
+ 'AIC_CLLI': {
+ 'type': 'string',
+ 'description': 'AIC Site CLLI',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': 'ATLMY8GA'
+ },
+ 'ASN': {
+ 'type': 'string',
+ 'description': 'AV/PE',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': 'AV_vPE'
+ },
+ 'vnf_instance_name': {
+ 'type': 'string',
+ 'description': 'The hostname assigned to the vpe.',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': 'mtnj309me6'
+ }
+ },
+ 'commands': {
+ 'vnf_config_template_version': {
+ 'displayName': 'vnf_config_template_version',
+ 'command': 'get_input',
+ 'inputName': '2017488_adiodvpe0_vnf_config_template_version'
+ },
+ 'bandwidth_units': {
+ 'displayName': 'bandwidth_units',
+ 'command': 'get_input',
+ 'inputName': 'adiodvpe0_bandwidth_units'
+ },
+ 'bandwidth': {'displayName': 'bandwidth', 'command': 'get_input', 'inputName': 'adiodvpe0_bandwidth'},
+ 'AIC_CLLI': {'displayName': 'AIC_CLLI', 'command': 'get_input', 'inputName': '2017488_adiodvpe0_AIC_CLLI'},
+ 'ASN': {'displayName': 'ASN', 'command': 'get_input', 'inputName': '2017488_adiodvpe0_ASN'},
+ 'vnf_instance_name': {
+ 'displayName': 'vnf_instance_name',
+ 'command': 'get_input',
+ 'inputName': '2017488_adiodvpe0_vnf_instance_name'
+ }
+ },
+ 'properties': {
+ 'vmxvre_retype': 'RE-VMX',
+ 'vnf_config_template_version': 'get_input:2017488_adiodvpe0_vnf_config_template_version',
+ 'sriov44_net_id': '48d399b3-11ee-48a8-94d2-f0ea94d6be8d',
+ 'int_ctl_net_id': '2f323477-6936-4d01-ac53-d849430281d9',
+ 'vmxvpfe_sriov41_0_port_mac': '00:11:22:EF:AC:DF',
+ 'int_ctl_net_name': 'VMX-INTXI',
+ 'vmx_int_ctl_prefix': '128.0.0.0',
+ 'sriov43_net_id': 'da349ca1-6de9-4548-be88-2d88e99bfef5',
+ 'sriov42_net_id': '760669ba-013d-4d9b-b0e7-4151fe2e6279',
+ 'sriov41_net_id': '25ad52d5-c165-40f8-b3b0-ddfc2373280a',
+ 'nf_type': 'vPE',
+ 'vmxvpfe_int_ctl_ip_1': '128.0.0.16',
+ 'is_AVPN_service': 'false',
+ 'vmx_RSG_name': 'vREXI-affinity',
+ 'vmx_int_ctl_forwarding': 'l2',
+ 'vmxvre_oam_ip_0': '10.40.123.5',
+ 'vmxvpfe_sriov44_0_port_mac': '00:11:22:EF:AC:DF',
+ 'vmxvpfe_sriov41_0_port_vlanstrip': 'false',
+ 'vmxvpfe_sriov42_0_port_vlanfilter': '4001',
+ 'vmxvpfe_sriov44_0_port_unknownunicastallow': 'true',
+ 'vmxvre_image_name_0': 'VRE-ENGINE_17.2-S2.1.qcow2',
+ 'vmxvre_instance': '0',
+ 'vmxvpfe_sriov43_0_port_mac': '00:11:22:EF:AC:DF',
+ 'vmxvre_flavor_name': 'ns.c1r16d32.v5',
+ 'vmxvpfe_volume_size_0': '40.0',
+ 'vmxvpfe_sriov43_0_port_vlanfilter': '4001',
+ 'nf_naming': '{ecomp_generated_naming=true}',
+ 'nf_naming_code': 'Navneet',
+ 'vmxvre_name_0': 'vREXI',
+ 'vmxvpfe_sriov42_0_port_vlanstrip': 'false',
+ 'vmxvpfe_volume_name_0': 'vPFEXI_FBVolume',
+ 'vmx_RSG_id': 'bd89a33c-13c3-4a04-8fde-1a57eb123141',
+ 'vmxvpfe_image_name_0': 'VPE_ROUTING-ENGINE_17.2R1-S2.1.qcow2',
+ 'vmxvpfe_sriov43_0_port_unknownunicastallow': 'true',
+ 'vmxvpfe_sriov44_0_port_unknownmulticastallow': 'true',
+ 'vmxvre_console': 'vidconsole',
+ 'vmxvpfe_sriov44_0_port_vlanfilter': '4001',
+ 'vmxvpfe_sriov42_0_port_mac': '00:11:22:EF:AC:DF',
+ 'vmxvpfe_volume_id_0': '47cede15-da2f-4397-a101-aa683220aff3',
+ 'vmxvpfe_sriov42_0_port_unknownmulticastallow': 'true',
+ 'vmxvpfe_sriov44_0_port_vlanstrip': 'false',
+ 'vf_module_id': '123',
+ 'nf_function': 'JAI',
+ 'vmxvpfe_sriov43_0_port_unknownmulticastallow': 'true',
+ 'vmxvre_int_ctl_ip_0': '128.0.0.1',
+ 'AIC_CLLI': 'get_input:2017488_adiodvpe0_AIC_CLLI',
+ 'vnf_name': 'mtnj309me6vre',
+ 'vmxvpfe_sriov41_0_port_unknownunicastallow': 'true',
+ 'vmxvre_volume_type_1': 'HITACHI',
+ 'vmxvpfe_sriov44_0_port_broadcastallow': 'true',
+ 'vmxvre_volume_type_0': 'HITACHI',
+ 'vmxvpfe_volume_type_0': 'HITACHI',
+ 'vmxvpfe_sriov43_0_port_broadcastallow': 'true',
+ 'bandwidth_units': 'get_input:adiodvpe0_bandwidth_units',
+ 'vnf_id': '123',
+ 'vmxvre_oam_prefix': '24',
+ 'availability_zone_0': 'mtpocfo-kvm-az01',
+ 'ASN': 'get_input:2017488_adiodvpe0_ASN',
+ 'vmxvre_chassis_i2cid': '161',
+ 'vmxvpfe_name_0': 'vPFEXI',
+ 'bandwidth': 'get_input:adiodvpe0_bandwidth',
+ 'availability_zone_max_count': '1',
+ 'vmxvre_volume_size_0': '45.0',
+ 'vmxvre_volume_size_1': '50.0',
+ 'vmxvpfe_sriov42_0_port_broadcastallow': 'true',
+ 'vmxvre_oam_gateway': '10.40.123.1',
+ 'vmxvre_volume_name_1': 'vREXI_FAVolume',
+ 'vmxvre_ore_present': '0',
+ 'vmxvre_volume_name_0': 'vREXI_FBVolume',
+ 'vmxvre_type': '0',
+ 'vnf_instance_name': 'get_input:2017488_adiodvpe0_vnf_instance_name',
+ 'vmxvpfe_sriov41_0_port_unknownmulticastallow': 'true',
+ 'oam_net_id': 'b95eeb1d-d55d-4827-abb4-8ebb94941429',
+ 'vmx_int_ctl_len': '24',
+ 'vmxvpfe_sriov43_0_port_vlanstrip': 'false',
+ 'vmxvpfe_sriov41_0_port_broadcastallow': 'true',
+ 'vmxvre_volume_id_1': '6e86797e-03cd-4fdc-ba72-2957119c746d',
+ 'vmxvpfe_sriov41_0_port_vlanfilter': '4001',
+ 'nf_role': 'Testing',
+ 'vmxvre_volume_id_0': 'f4eacb79-f687-4e9d-b760-21847c8bb15a',
+ 'vmxvpfe_sriov42_0_port_unknownunicastallow': 'true',
+ 'vmxvpfe_flavor_name': 'ns.c20r16d25.v5'
+ },
+ 'type': 'VF',
+ 'modelCustomizationName': '2017488_ADIODvPE 0',
+ 'vfModules': {
+ '2017488_adiodvpe0..2017488AdiodVpe..ADIOD_vRE_BV..module-1': {
+ 'uuid': '25284168-24bb-4698-8cb4-3f509146eca5',
+ 'invariantUuid': '7253ff5c-97f0-4b8b-937c-77aeb4d79aa1',
+ 'customizationUuid': 'f7e7c365-60cf-49a9-9ebf-a1aa11b9d401',
+ 'description': null,
+ 'name': '2017488AdiodVpe..ADIOD_vRE_BV..module-1',
+ 'version': '6',
+ 'modelCustomizationName': '2017488AdiodVpe..ADIOD_vRE_BV..module-1',
+ 'properties': {'minCountInstances': 0, 'maxCountInstances': null, 'initialCount': 0},
+ 'commands': {},
+ 'volumeGroupAllowed': true,
+ 'inputs': {
+ '2017488_adiodvpe0_vnf_config_template_version': {
+ 'type': 'string',
+ 'description': 'VPE Software Version',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': '17.2'
+ },
+ '2017488_adiodvpe0_AIC_CLLI': {
+ 'type': 'string',
+ 'description': 'AIC Site CLLI',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': 'ATLMY8GA'
+ }
+ }
+ },
+ '2017488_adiodvpe0..2017488AdiodVpe..ADIOD_base_vPE_BV..module-0': {
+ 'uuid': 'f8360508-3f17-4414-a2ed-6bc71161e8db',
+ 'invariantUuid': 'b34833bb-6aa9-4ad6-a831-70b06367a091',
+ 'customizationUuid': 'a55961b2-2065-4ab0-a5b7-2fcee1c227e3',
+ 'description': null,
+ 'name': '2017488AdiodVpe..ADIOD_base_vPE_BV..module-0',
+ 'version': '5',
+ 'modelCustomizationName': '2017488AdiodVpe..ADIOD_base_vPE_BV..module-0',
+ 'properties': {'minCountInstances': 1, 'maxCountInstances': 1, 'initialCount': 1},
+ 'commands': {},
+ 'volumeGroupAllowed': false,
+ 'inputs': {
+ '2017488_adiodvpe0_ASN': {
+ 'type': 'string',
+ 'description': 'AV/PE',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': 'AV_vPE'
+ },
+ 'adiodvpe0_bandwidth': {
+ 'type': 'string',
+ 'description': 'Requested VPE bandwidth',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': '10'
+ }
+ }
+ },
+ '2017488_adiodvpe0..2017488AdiodVpe..ADIOD_vPFE_BV..module-2': {
+ 'uuid': '0a0dd9d4-31d3-4c3a-ae89-a02f383e6a9a',
+ 'invariantUuid': 'eff8cc59-53a1-4101-aed7-8cf24ecf8339',
+ 'customizationUuid': '3cd946bb-50e0-40d8-96d3-c9023520b557',
+ 'description': null,
+ 'name': '2017488AdiodVpe..ADIOD_vPFE_BV..module-2',
+ 'version': '6',
+ 'modelCustomizationName': '2017488AdiodVpe..ADIOD_vPFE_BV..module-2',
+ 'properties': {'minCountInstances': 0, 'maxCountInstances': null, 'initialCount': 0},
+ 'commands': {},
+ 'volumeGroupAllowed': true,
+ 'inputs': {}
+ }
+ },
+ 'volumeGroups': {
+ '2017488_adiodvpe0..2017488AdiodVpe..ADIOD_vRE_BV..module-1': {
+ 'uuid': '25284168-24bb-4698-8cb4-3f509146eca5',
+ 'invariantUuid': '7253ff5c-97f0-4b8b-937c-77aeb4d79aa1',
+ 'customizationUuid': 'f7e7c365-60cf-49a9-9ebf-a1aa11b9d401',
+ 'description': null,
+ 'name': '2017488AdiodVpe..ADIOD_vRE_BV..module-1',
+ 'version': '6',
+ 'modelCustomizationName': '2017488AdiodVpe..ADIOD_vRE_BV..module-1',
+ 'properties': {'minCountInstances': 0, 'maxCountInstances': null, 'initialCount': 0}
+ },
+ '2017488_adiodvpe0..2017488AdiodVpe..ADIOD_vPFE_BV..module-2': {
+ 'uuid': '0a0dd9d4-31d3-4c3a-ae89-a02f383e6a9a',
+ 'invariantUuid': 'eff8cc59-53a1-4101-aed7-8cf24ecf8339',
+ 'customizationUuid': '3cd946bb-50e0-40d8-96d3-c9023520b557',
+ 'description': null,
+ 'name': '2017488AdiodVpe..ADIOD_vPFE_BV..module-2',
+ 'version': '6',
+ 'modelCustomizationName': '2017488AdiodVpe..ADIOD_vPFE_BV..module-2',
+ 'properties': {'minCountInstances': 0, 'maxCountInstances': null, 'initialCount': 0}
+ }
+ }
+ }
+ },
+ 'vfModules': {
+ '2017488_adiodvpe0..2017488AdiodVpe..ADIOD_vRE_BV..module-1': {
+ 'uuid': '25284168-24bb-4698-8cb4-3f509146eca5',
+ 'invariantUuid': '7253ff5c-97f0-4b8b-937c-77aeb4d79aa1',
+ 'customizationUuid': 'f7e7c365-60cf-49a9-9ebf-a1aa11b9d401',
+ 'description': null,
+ 'name': '2017488AdiodVpe..ADIOD_vRE_BV..module-1',
+ 'version': '6',
+ 'modelCustomizationName': '2017488AdiodVpe..ADIOD_vRE_BV..module-1',
+ 'properties': {'minCountInstances': 0, 'maxCountInstances': null, 'initialCount': 0},
+ 'commands': {},
+ 'volumeGroupAllowed': true
+ },
+ '2017488_adiodvpe0..2017488AdiodVpe..ADIOD_base_vPE_BV..module-0': {
+ 'uuid': 'f8360508-3f17-4414-a2ed-6bc71161e8db',
+ 'invariantUuid': 'b34833bb-6aa9-4ad6-a831-70b06367a091',
+ 'customizationUuid': 'a55961b2-2065-4ab0-a5b7-2fcee1c227e3',
+ 'description': null,
+ 'name': '2017488AdiodVpe..ADIOD_base_vPE_BV..module-0',
+ 'version': '5',
+ 'modelCustomizationName': '2017488AdiodVpe..ADIOD_base_vPE_BV..module-0',
+ 'properties': {'minCountInstances': 1, 'maxCountInstances': 1, 'initialCount': 1},
+ 'commands': {},
+ 'volumeGroupAllowed': false
+ },
+ '2017488_adiodvpe0..2017488AdiodVpe..ADIOD_vPFE_BV..module-2': {
+ 'uuid': '0a0dd9d4-31d3-4c3a-ae89-a02f383e6a9a',
+ 'invariantUuid': 'eff8cc59-53a1-4101-aed7-8cf24ecf8339',
+ 'customizationUuid': '3cd946bb-50e0-40d8-96d3-c9023520b557',
+ 'description': null,
+ 'name': '2017488AdiodVpe..ADIOD_vPFE_BV..module-2',
+ 'version': '6',
+ 'modelCustomizationName': '2017488AdiodVpe..ADIOD_vPFE_BV..module-2',
+ 'properties': {'minCountInstances': 0, 'maxCountInstances': null, 'initialCount': 0},
+ 'commands': {},
+ 'volumeGroupAllowed': true
+ }
+ },
+ 'networks': {},
+ 'collectionResource': {},
+ 'configurations': {},
+ 'serviceProxies': {},
+ 'pnfs': {}
+ }
+ ))
+ }
+
+});
diff --git a/vid-webpack-master/src/app/configuration/vid.configuration.ts b/vid-webpack-master/src/app/configuration/vid.configuration.ts
new file mode 100644
index 000000000..2430d3ba5
--- /dev/null
+++ b/vid-webpack-master/src/app/configuration/vid.configuration.ts
@@ -0,0 +1,98 @@
+export class VidConfiguration {
+
+ public static VNF_STATUS_CHECK_ENABLED = false;
+
+ /*
+ * UPLOAD_SUPPLEMENTARY_STATUS_CHECK_ENABLED: Determines the Property to Govern Presence of
+ * Upload Supplementary File on Volume Group Screen.
+ * Set to false, to disable the check.
+ */
+ public static UPLOAD_SUPPLEMENTARY_STATUS_CHECK_ENABLED = false;
+
+ /*
+ * List of valid VNF status combinations
+ */
+ public static VNF_VALID_STATUS_LIST = [
+ {
+ 'provStatus': 'preprov',
+ 'orchestrationStatus': 'pending-create',
+ 'inMaint': false,
+ 'operationalStatus': null
+ },
+ {
+ 'provStatus': 'preprov',
+ 'orchestrationStatus': 'created',
+ 'inMaint': false,
+ 'operationalStatus': null
+ },
+ {
+ 'provStatus': 'preprov',
+ 'orchestrationStatus': 'active',
+ 'inMaint': false,
+ 'operationalStatus': null
+ },
+ {
+ 'provStatus': 'nvtprov',
+ 'orchestrationStatus': 'active',
+ 'inMaint': false,
+ 'operationalStatus': null
+ },
+ {
+ 'provStatus': 'prov',
+ 'orchestrationStatus': 'active',
+ 'inMaint': false,
+ 'operationalStatus': 'out-of-service-path'
+ },
+ {
+ 'provStatus': 'prov',
+ 'orchestrationStatus': 'activated',
+ 'inMaint': false,
+ 'operationalStatus': 'out-of-service-path'
+ }
+ ];
+
+ /*
+ * The model status VID uses to query SDC for a list of models. The possible values are:
+ * DISTRIBUTION_NOT_APPROVED,
+ * DISTRIBUTION_APPROVED,
+ * DISTRIBUTED,
+ * DISTRIBUTION_REJECTED,
+ * ALL,
+ * In the production env, this should always be set to DISTRIBUTED
+ */
+ public static ASDC_MODEL_STATUS = 'DISTRIBUTED';
+
+ /*
+ * Max number of times that VID will poll MSO for a given request status
+ */
+ public static MSO_MAX_POLLS = 10;
+
+ /*
+ * Number of msecs that VID will wait between MSO polls.
+ */
+ public static MSO_POLLING_INTERVAL_MSECS = 10000;
+
+ public static SCHEDULER_POLLING_INTERVAL_MSECS = 10000;
+
+ public static SCHEDULER_MAX_POLLS = 10;
+
+ public static COMPONENT_LIST_NAMED_QUERY_ID = '0367193e-c785-4d5f-9cb8-7bc89dc9ddb7';
+
+ /*
+ * List of all service model invariant UUIDs that need macro instantiation.
+ * Example:
+ * MACRO_SERVICES : ['3cf30cbb-5fe7-4fb3-b049-559a4997b221', 'b135a703-bab5-4295-a37f-580a4f2d0961']
+ *
+ */
+ public static MACRO_SERVICES = ['c9514b73-3dfe-4d7e-9146-b318d48655d9', '93150ffa-00c6-4ea0-85f2-3536ca46ebd2',
+ '2b54297f-72e7-4a94-b451-72df88d0be0b',
+ 'd27e42cf-087e-4d31-88ac-6c4b7585f800',
+ 'ec0c4bab-c272-4dab-b087-875031bb0c9f', '0311f998-9268-4fd6-bbba-afff15087b72',
+ '43596836-ae36-4608-a987-6608ede10dac', '306caa85-74c7-48a9-aa22-7e3a564b957a',
+ 'e49fbd11-e60c-4a8e-b4bf-30fbe8f4fcc0'];
+
+ public static SCHEDULER_CALLBACK_URL = 'https://vid-web-ete.ecomp.cci.att.com:8000/vid/change-management/workflow/';
+
+ public static SCHEDULER_PORTAL_URL = 'http://www.ecomp.att.com';
+
+}
diff --git a/vid-webpack-master/src/app/drawingBoard/available-models-tree/available-models-tree.component.html b/vid-webpack-master/src/app/drawingBoard/available-models-tree/available-models-tree.component.html
new file mode 100644
index 000000000..5eb977325
--- /dev/null
+++ b/vid-webpack-master/src/app/drawingBoard/available-models-tree/available-models-tree.component.html
@@ -0,0 +1,35 @@
+<div class="available-models-tree">
+ <h5>
+ <span>SERVICE MODEL:</span>
+ <span id="service-model-name">{{service | serviceInfo: _store: serviceModelId : 'name'}}</span>
+ </h5>
+ <div class="available-models-content-wrapper">
+ <div class="search-container">
+ <input [attr.data-tests-id]="'search-left-tree'" #filter (keyup)="searchTree(filter.value, $event)" placeholder="Filter..."/>
+ <span class="icon-search"></span>
+ </div>
+
+ <tree-root #tree [attr.data-tests-id]="'available-models-tree'" [nodes]="nodes" [options]="options">
+ <ng-template #treeNodeTemplate let-node let-index="index">
+ <div [attr.data-tests-id]="'node-'+node.data.name" (click)="selectNode(node)" [ngClass]="{'selected': index , 'isParent': node.data.type !== 'VFmodule' , 'isChild': node.data.type === 'VFmodule' }">
+ <span class="vf-type">{{node.data.type.substring(0,1)}}</span>
+ <span class="span-name" [innerHTML]=" isFilterEnabled ? (node.data.name | highlight : filter.value) : (node.data.name)"></span>
+ <span class="actions">
+ <span class="number-button" *ngIf="isShowNodeCount(node)">
+ <span>{{getNodeCount(node)}}</span>
+ </span>
+ <span class="icon-v" *ngIf="isShowIconV(node)">
+ <span ></span>
+ </span>
+ <span class="icon-plus" *ngIf="isShowIconAdd(node)">
+ <span tooltip="Add" [attr.data-tests-id]="'node-'+node.data.name+'-add-btn'" (click)="onClickAdd($event,node)">
+ <i class="fa fa-plus-circle" aria-hidden="true"></i>
+ </span>
+ </span>
+ </span>
+ </div>
+ </ng-template>
+ </tree-root>
+
+ </div>
+</div>
diff --git a/vid-webpack-master/src/app/drawingBoard/available-models-tree/available-models-tree.component.scss b/vid-webpack-master/src/app/drawingBoard/available-models-tree/available-models-tree.component.scss
new file mode 100644
index 000000000..44f94109a
--- /dev/null
+++ b/vid-webpack-master/src/app/drawingBoard/available-models-tree/available-models-tree.component.scss
@@ -0,0 +1,398 @@
+available-models-tree {
+ .available-models-tree {
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ line-height: 14px;
+ border-right: #D2D2D2 1.5px solid;
+ min-width: 340px;
+ h5 {
+ font-family: OpenSans-Semibold;
+ color: #5A5A5A;
+ background-color: #F2F2F2;
+ margin: 0;
+ padding: 15px;
+ padding-left: 20px;
+ span {
+ vertical-align: middle;
+ &:first-child {
+ font-size: 12px;
+ color: #191919;
+ }
+ }
+ }
+ .available-models-content-wrapper {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ padding: 20px;
+ background-color: #F2F2F2;
+ .search-container {
+ margin-bottom: 30px;
+ width: 100%;
+ display: flex;
+ background: #FFFFFF;
+ border: 1px solid #D2D2D2;
+ border-radius: 2px;
+ height: 40px;
+ min-width: 40px;
+ font-family: OpenSans-Italic;
+ color: #959595;
+ input {
+ flex: 1;
+ border: 0;
+ padding-left: 10px;
+ outline: 0;
+ }
+ .icon-search {
+ display: flex;
+ width: 40px;
+ &:after {
+ content: "\e92e";
+ cursor: pointer;
+ font-size: 20px;
+ font-weight: 600;
+ text-align: center;
+ display: inline-block;
+ flex: auto;
+ align-self: center;
+ }
+ }
+ }
+ tree-root {
+ flex: 1;
+ display: flex;
+ }
+ tree-viewport {
+ flex: 1;
+ height: auto;
+ overflow: auto;
+ padding-top: 5px;
+ .tree-node {
+ color: #5A5A5A;
+ font-size: 13px;
+ white-space: normal;
+ word-break: break-all;
+ tree-node-drop-slot {
+ .node-drop-slot {
+ display: none;
+ }
+ }
+ &.tree-node-disabled {
+ color: #D2D2D2;
+ cursor: default;
+ pointer-events: none;
+ }
+ &:not(.tree-node-disabled) {
+ >tree-node-wrapper {
+ .node-wrapper:hover {
+ color: #009FDB;
+ .node-content-wrapper {
+ tree-node-content {
+ > div {
+ span.actions {
+ .number-button {
+ span {
+ //background-color: #009FDB;
+ }
+ }
+ .icon-plus span:before {
+ display: inline-block;
+ color: #5A5A5A;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ &.tree-node-focused:not(.tree-node-disabled) {
+ & > tree-node-wrapper {
+ .node-wrapper {
+ color: #009FDB;
+ .node-content-wrapper-focused,
+ .node-content-wrapper:hover {
+ background: none;
+ box-shadow: none;
+ tree-node-content {
+ > div {
+ span.actions {
+ .number-button {
+ span {
+ //background-color: #009FDB;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ tree-node-wrapper {
+ .node-wrapper {
+ height: 36px;
+ tree-node-expander {
+ font-family: 'icomoon' !important;
+ height: 100%;
+ .toggle-children-wrapper {
+ padding: 0;
+ display: block;
+ height: 100%;
+ span.toggle-children {
+ display: flex;
+ width: 20px;
+ top: 0;
+ height: inherit;
+ background-image: none;
+ &:before {
+ content: "\e900";
+ font-weight: 600;
+ text-align: center;
+ display: inline-block;
+ flex: auto;
+ align-self: center;
+ font-size: 20px;
+ }
+ }
+ }
+ .toggle-children-wrapper-expanded {
+ span.toggle-children {
+ transform: none;
+ &:before {
+ content: "\e930";
+ }
+ }
+ }
+ .toggle-children-placeholder {
+ width: 20px;
+ }
+ }
+ .node-content-wrapper {
+ padding: 0;
+ background: none;
+ box-shadow: none;
+ height: 100%;
+ flex: 1;
+ min-width: 0;
+ border-left: 1px solid #D2D2D2;
+ tree-node-content {
+ > div {
+ height: 100%;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding-left: 10px;
+ span {
+ &.actions {
+ height: 100%;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ >span {
+ width: 45px;
+ max-width: 45px;
+ text-align: center;
+ }
+ .number-button {
+ width: 30px;
+ padding-left: 0;
+ text-align: center;
+ span {
+ display: block;
+ font-size: 11px;
+ }
+ }
+ .icon-v {
+ width: 45px;
+ span:before {
+ content: "\e932";
+ color: #5A5A5A;
+ font-size: 16px;
+ text-align: center;
+ display: inline-block;
+ vertical-align: baseline;
+ }
+ }
+ .icon-plus {
+ width: 45px;
+ span {
+ &:before {
+ //content: "\e901";
+ //fill:#009FDB;
+ //color: #009FDB;
+ //font-size: 16px;
+ //text-align: center;
+ //display: none;
+ //vertical-align: baseline;
+ }
+ &:hover:before {
+ //color: #009FDB !important;
+
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ }
+ }
+ tree-node-children {
+ .tree-children {
+ padding-left: 20px;
+ }
+ }
+ }
+ }
+
+ }
+ }
+}
+.highlight {
+ background-color: #9DD9EF;
+}
+
+#drawing-board-tree{
+ .tree-node.tree-node-expanded.tree-node-focused {
+ border: 1px solid #009FDB;
+ }
+
+}
+
+available-models-tree {
+
+ .tree-root {
+ margin-top: 35px;
+ }
+
+ tree-node-expander {
+ background: #FFFFFF;
+ border: 1px solid #D2D2D2;
+ border-right: none;
+ width: 45px;
+ padding-left: 12px;
+ }
+
+ .node-content-wrapper {
+ border: none;
+ }
+
+ tree-node-wrapper tree-node-expander{
+ background: none !important;
+ border: none !important;
+ }
+
+ tree-node-content div {
+ background: white;
+ }
+
+ .node-wrapper {
+ height: 45px !important;
+ background: #FFFFFF;
+ border: 1px solid #D2D2D2;
+ }
+
+ tree-node-collection div {
+ margin-top: 0px;
+ }
+
+ .tree-node-leaf .node-wrapper tree-node-expander {
+ display: none;
+ }
+
+ .tree-children {
+ padding: 20px;
+ }
+
+ .tree-node.tree-node-expanded.tree-node-focused {
+ border: 1px solid #009FDB;
+ }
+
+ .tree-node.tree-node-expanded {
+ border: 1px solid rgba(128, 128, 128, 0.72);
+ margin-bottom: 10px;
+ }
+
+ .tree-children {
+ padding-left: 0;
+ }
+
+ tree-node-content .actions .number-button {
+ height: 45px;
+ padding-top: 14px;
+ border: 1px solid #D2D2D2;
+ padding-left: 0;
+ span {
+ background: none;
+ font-size: 11px;
+ color: #5A5A5A;
+ }
+ }
+
+
+
+ .node-content-wrapper.node-content-wrapper-focused tree-node-content div{
+ background: #009FDB !important;
+ color: white;
+
+ .isParent {
+ border-left: 1px solid #009FDB;
+ }
+
+ .number-button span{
+ color: white !important;
+ }
+
+ .icon-v span:before{
+ color: white !important;
+ }
+ }
+
+ .vf-type {
+ width: 20px;
+ height: 45px;
+ padding-top: 16px;
+ border-right: 1px solid #D2D2D2;
+
+ }
+
+ .isParent {
+ width: 100%;
+ padding-left: 5px;
+ }
+
+ .tree-node-expanded .isChild .vf-type {
+ display: none;
+ }
+
+ .isParent .span-name {
+ width: 100%;
+ padding-left: 10px;
+ }
+
+ .toggle-children-wrapper.toggle-children-wrapper-expanded {
+ .toggle-children:before {
+ color: #009FDB;
+ }
+ }
+
+ .tree-node.tree-node-expanded .tree-children {
+ border: 1px solid rgba(128, 128, 128, 0.72);
+ }
+
+ .tree-node.tree-node-expanded.tree-node-focused .tree-children {
+ border: 1px solid #009fdb;
+ }
+
+ .tree-node-leaf .node-wrapper{
+ margin-left: 45px;
+ border-left: none;
+ }
+}
+
+
+
diff --git a/vid-webpack-master/src/app/drawingBoard/available-models-tree/available-models-tree.component.ts b/vid-webpack-master/src/app/drawingBoard/available-models-tree/available-models-tree.component.ts
new file mode 100644
index 000000000..4e5819e4c
--- /dev/null
+++ b/vid-webpack-master/src/app/drawingBoard/available-models-tree/available-models-tree.component.ts
@@ -0,0 +1,166 @@
+import {Component, EventEmitter, Output, ViewChild} from '@angular/core';
+import {ITreeOptions, TreeComponent} from 'angular-tree-component';
+import '../../../../node_modules/angular-tree-component/dist/angular-tree-component.css';
+import {IDType, ITreeNode} from 'angular-tree-component/dist/defs/api';
+import {DialogService} from 'ng2-bootstrap-modal';
+import {AvailableModelsTreeService} from './available-models-tree.service';
+import {NgRedux} from "@angular-redux/store";
+import {ActivatedRoute} from '@angular/router';
+import {AppState} from '../../store/reducers';
+import {AaiService} from '../../services/aaiService/aai.service';
+import {ServicePlanningService} from '../../services/service-planning.service';
+import {VnfPopupComponent} from '../../components/vnf-popup/vnf-popup.components';
+import {ServiceNodeTypes} from '../../shared/models/ServiceNodeTypes';
+import {VfModuleMap} from '../../shared/models/vfModulesMap';
+import {IframeService} from "../../shared/utils/iframe.service";
+import {createVFModuleInstance} from "../../service.actions";
+import {DefaultDataGeneratorService} from "../../shared/services/defaultDataServiceGenerator/default.data.generator.service";
+
+
+@Component({
+ selector: 'available-models-tree',
+ templateUrl: './available-models-tree.component.html',
+ styleUrls: ['./available-models-tree.component.scss']
+})
+
+
+export class AvailableModelsTreeComponent{
+
+ serviceModelId: string;
+ serviceHierarchy;
+ parentElementClassName = 'content';
+ _store : NgRedux<AppState>;
+ constructor(private _servicePlanningService: ServicePlanningService,
+ private _iframeService: IframeService,
+ private _aaiService: AaiService,
+ private route: ActivatedRoute,
+ private dialogService: DialogService,
+ private _availableModelsTreeService: AvailableModelsTreeService,
+ private _defaultDataGeneratorService: DefaultDataGeneratorService,
+ private store: NgRedux<AppState>) {
+ this._store = store;
+ this.route
+ .queryParams
+ .subscribe(params => {
+ this.serviceModelId = params['serviceModelId'];
+ this._aaiService.getServiceModelById(this.serviceModelId).subscribe(
+ value => {
+ this.serviceHierarchy = value;
+ this.nodes = this._servicePlanningService.convertServiceModelToTreeNodes(this.serviceHierarchy);
+ },
+ error => {
+ console.log('error is ', error)
+ }
+ );
+ });
+
+ }
+
+ @Output()
+ highlightInstances: EventEmitter<number> = new EventEmitter<number>();
+ @ViewChild('tree') tree: TreeComponent;
+
+ nodes = [];
+ service = {name: ''};
+ isFilterEnabled: boolean = false;
+
+ options: ITreeOptions = {
+ nodeHeight: 36,
+ dropSlotHeight: 0,
+ nodeClass: (node: ITreeNode) => {
+ if(node.data.type === ServiceNodeTypes.VFmodule && !this.getNodeCount(node.parent))
+ {
+ node.data.disabled = true;
+ return 'tree-node tree-node-disabled';
+ }
+ node.data.disabled = false;
+ return 'tree-node';
+ }
+ };
+
+ expandParentByNodeId(id: IDType): void {
+ this.tree.treeModel.getNodeById(id).parent.expand();
+ }
+
+ searchTree(searchText: string, event: KeyboardEvent): void {
+ if (searchText === '') {
+ return;
+ }
+ this.isFilterEnabled = event.key === 'Delete' || event.key === 'Backspace' || searchText.length > 1;
+ if (this.isFilterEnabled) {
+ let __this = this;
+ let results: ITreeNode[] = [];
+ this.nodes.forEach(function (node) {
+ __this.searchTreeNode(node, searchText, results);
+ });
+ results.forEach(function (result) {
+ __this.expandParentByNodeId(result.id)
+ });
+ }
+ }
+
+ searchTreeNode(node, searchText: string, results): void {
+ if (node.name.toLowerCase().indexOf(searchText.toLowerCase()) != -1) {
+ results.push(node);
+ }
+ if (node.children != null) {
+ for (let i = 0; i < node.children.length; i++) {
+ this.searchTreeNode(node.children[i], searchText, results);
+ }
+ }
+ }
+
+ selectNode(node: ITreeNode): void {
+ node.expand();
+ this.highlightInstances.emit(node.data.id);
+ }
+
+ onClickAdd(e: MouseEvent, node: ITreeNode): void {
+ let data = node.data;
+ let dynamicInputs = data.dynamicInputs;
+ let userProvidedNaming:boolean = data.userProvidedNaming;
+ let type:string = data.type;
+ if(!this.store.getState().global.flags['FLAG_SETTING_DEFAULTS_IN_DRAWING_BOARD']|| node.data.type === ServiceNodeTypes.VF || this._availableModelsTreeService.shouldOpenDialog(type, dynamicInputs, userProvidedNaming)) {
+ this._iframeService.addClassOpenModal(this.parentElementClassName);
+ this.dialogService.addDialog(VnfPopupComponent, {
+ serviceModelId: this.serviceModelId,
+ parentModelName: node.parent && node.parent.data.name,
+ modelName: data.name,
+ modelType: type,
+ dynamicInputs: dynamicInputs,
+ userProvidedNaming: userProvidedNaming,
+ isNewVfModule : true
+ });
+ }
+ else {
+ let vfModule = this._defaultDataGeneratorService.generateVFModule(this.serviceHierarchy, node.parent.data.name, node.data.name);
+ this.store.dispatch(createVFModuleInstance(vfModule, node.data.name, this.serviceModelId));
+ }
+ e.preventDefault();
+ e.stopPropagation();
+ }
+
+ getNodeCount(node: ITreeNode): number {
+ let modelName: string = node.data.name;
+ if (ServicePlanningService.isVfModule(node)) {
+ let parentVnfModelName = node.parent.data.name;
+ let vfModuleMap: VfModuleMap = this._servicePlanningService.getVfModuleMap(this.serviceModelId, parentVnfModelName, modelName);
+ return vfModuleMap ? Object.keys(vfModuleMap).length : 0;
+ } else if (ServicePlanningService.isVnf(node)) {
+ let vnfInstance = this._servicePlanningService.getVnfInstance(this.serviceModelId, modelName);
+ return vnfInstance ? 1 : 0;
+ }
+ }
+
+ isShowIconV(node: ITreeNode): boolean {
+ return this.getNodeCount(node) > 0;
+ }
+
+ isShowNodeCount(node: ITreeNode): boolean {
+ return this.getNodeCount(node) > 0;
+ }
+
+ isShowIconAdd(node: ITreeNode): boolean {
+ return this._availableModelsTreeService.shouldShowAddIcon(node, this.store.getState().service.serviceHierarchy, this.serviceModelId, this.getNodeCount(node));
+ }
+}
diff --git a/vid-webpack-master/src/app/drawingBoard/available-models-tree/available-models-tree.service.spec.ts b/vid-webpack-master/src/app/drawingBoard/available-models-tree/available-models-tree.service.spec.ts
new file mode 100644
index 000000000..10cbb0d8f
--- /dev/null
+++ b/vid-webpack-master/src/app/drawingBoard/available-models-tree/available-models-tree.service.spec.ts
@@ -0,0 +1,450 @@
+import {TestBed, getTestBed} from '@angular/core/testing';
+import {
+ HttpClientTestingModule,
+ HttpTestingController
+} from '@angular/common/http/testing';
+import {AvailableModelsTreeService} from './available-models-tree.service';
+import {ServicePlanningService} from "../../services/service-planning.service";
+import {ServiceNodeTypes} from "../../shared/models/ServiceNodeTypes";
+import {NgRedux} from "@angular-redux/store";
+import {MockAppStore} from "../../services/service-planning.service.spec";
+
+describe('Available Models Tree Service', () => {
+ let injector;
+ let service: AvailableModelsTreeService;
+ let httpMock: HttpTestingController;
+
+ beforeEach(() => {
+
+ TestBed.configureTestingModule({
+ imports: [HttpClientTestingModule],
+ providers: [AvailableModelsTreeService,
+ ServicePlanningService,
+ {provide: NgRedux, useClass: MockAppStore}]
+ });
+
+ injector = getTestBed();
+ service = injector.get(AvailableModelsTreeService);
+ httpMock = injector.get(HttpTestingController);
+ });
+
+ describe('#shouldShowAddIcon', () => {
+ it('should return true if number of current vnf modules is under the max', (done: DoneFn) => {
+ let treeNode = {
+ data: {
+ children: [],
+ name: 'vf_vmee0..VfVmee..base_vmme..module-0'
+ }
+ };
+
+ let serviceHierarchy = getSericeServiceHierarchy();
+ let result = service.shouldShowAddIcon(treeNode, serviceHierarchy, '6e59c5de-f052-46fa-aa7e-2fca9d674c44', 0);
+ expect(result).toBeTruthy();
+ done();
+ });
+
+ it('should return false if number of current vnf modules are more than max', (done: DoneFn) => {
+ let treeNode = {
+ data: {
+ children: [],
+ name: 'vf_vmee0..VfVmee..base_vmme..module-0'
+ }
+ };
+
+ let serviceHierarchy = getSericeServiceHierarchy();
+ let result = service.shouldShowAddIcon(treeNode, serviceHierarchy, '6e59c5de-f052-46fa-aa7e-2fca9d674c44', 2);
+ expect(result).toBeFalsy();
+ done();
+ });
+
+ it('should return true if number of current vnf modules are more than max and max is null', (done: DoneFn) => {
+ let treeNode = {
+ data: {
+ children: [],
+ name: 'vf_vmee0..VfVmee..base_vmme..module-0'
+ }
+ };
+
+ let serviceHierarchy = getSericeServiceHierarchy();
+ let result = service.shouldShowAddIcon(treeNode, serviceHierarchy, '6e59c5de-f052-46fa-aa7e-2fca9d674c44', 0);
+ expect(result).toBeTruthy();
+ done();
+ });
+ });
+
+ describe('#shouldOpenModalDialogOnAddInstance', () => {
+ let serviceHierarchy = getSericeServiceHierarchy();
+
+ it('should open popup on add instance', (done: DoneFn) => {
+ // add vnf should return true
+ let result = service.shouldOpenDialog(ServiceNodeTypes.VF, [], false);
+ expect(result).toBeTruthy();
+
+ // add vfModule with user provided naming should return true
+ result = service.shouldOpenDialog(ServiceNodeTypes.VFmodule, [], true);
+ expect(result).toBeTruthy();
+
+ // add vfModule with dynamicInputs without defaultValues should return true
+ result = service.shouldOpenDialog(ServiceNodeTypes.VFmodule, [{
+ id: '2017488_adiodvpe0_vnf_config_template_version',
+ type: 'string',
+ name: '2017488_adiodvpe0_vnf_config_template_version',
+ isRequired: true,
+ description: 'VPE Software Version'
+ }], false);
+ expect(result).toBeTruthy();
+
+ // add vfModule with dynamicInputs with defaultValues should return false
+ result = service.shouldOpenDialog(ServiceNodeTypes.VFmodule, [{
+ id: '2017488_adiodvpe0_vnf_config_template_version',
+ type: 'string',
+ name: '2017488_adiodvpe0_vnf_config_template_version',
+ value: '17.2',
+ isRequired: true,
+ description: 'VPE Software Version'
+ }], false);
+ expect(result).toBeFalsy();
+ done();
+ });
+ });
+
+ function getSericeServiceHierarchy() {
+ return JSON.parse(JSON.stringify(
+ {
+ '6e59c5de-f052-46fa-aa7e-2fca9d674c44': {
+ 'service': {
+ 'uuid': '6e59c5de-f052-46fa-aa7e-2fca9d674c44',
+ 'invariantUuid': 'e49fbd11-e60c-4a8e-b4bf-30fbe8f4fcc0',
+ 'name': 'ComplexService',
+ 'version': '1.0',
+ 'toscaModelURL': null,
+ 'category': 'Mobility',
+ 'serviceType': '',
+ 'serviceRole': '',
+ 'description': 'ComplexService',
+ 'serviceEcompNaming': 'true',
+ 'instantiationType': 'Macro',
+ 'inputs': {}
+ },
+ 'vnfs': {
+ 'VF_vMee 0': {
+ 'uuid': 'd6557200-ecf2-4641-8094-5393ae3aae60',
+ 'invariantUuid': '4160458e-f648-4b30-a176-43881ffffe9e',
+ 'description': 'VSP_vMee',
+ 'name': 'VF_vMee',
+ 'version': '2.0',
+ 'customizationUuid': '91415b44-753d-494c-926a-456a9172bbb9',
+ 'inputs': {},
+ 'commands': {},
+ 'properties': {
+ 'gpb2_Internal2_mac': '00:80:37:0E:02:22',
+ 'sctp-b-ipv6-egress_src_start_port': '0',
+ 'sctp-a-ipv6-egress_rule_application': 'any',
+ 'Internal2_allow_transit': 'true',
+ 'sctp-b-IPv6_ethertype': 'IPv6',
+ 'sctp-a-egress_rule_application': 'any',
+ 'sctp-b-ingress_action': 'pass',
+ 'sctp-b-ingress_rule_protocol': 'icmp',
+ 'ncb2_Internal1_mac': '00:80:37:0E:0F:12',
+ 'sctp-b-ipv6-ingress-src_start_port': '0.0',
+ 'ncb1_Internal2_mac': '00:80:37:0E:09:12',
+ 'fsb_volume_size_0': '320.0',
+ 'sctp-b-egress_src_addresses': 'local',
+ 'sctp-a-ipv6-ingress_ethertype': 'IPv4',
+ 'sctp-a-ipv6-ingress-dst_start_port': '0',
+ 'sctp-b-ipv6-ingress_rule_application': 'any',
+ 'domain_name': 'default-domain',
+ 'sctp-a-ingress_rule_protocol': 'icmp',
+ 'sctp-b-egress-src_start_port': '0.0',
+ 'sctp-a-egress_src_addresses': 'local',
+ 'sctp-b-display_name': 'epc-sctp-b-ipv4v6-sec-group',
+ 'sctp-a-egress-src_start_port': '0.0',
+ 'sctp-a-ingress_ethertype': 'IPv4',
+ 'sctp-b-ipv6-ingress-dst_end_port': '65535',
+ 'sctp-b-dst_subnet_prefix_v6': '::',
+ 'nf_naming': '{ecomp_generated_naming=true}',
+ 'sctp-a-ipv6-ingress_src_subnet_prefix': '0.0.0.0',
+ 'sctp-b-egress-dst_start_port': '0.0',
+ 'ncb_flavor_name': 'nv.c20r64d1',
+ 'gpb1_Internal1_mac': '00:80:37:0E:01:22',
+ 'sctp-b-egress_dst_subnet_prefix_len': '0.0',
+ 'Internal2_net_cidr': '169.255.0.0',
+ 'sctp-a-ingress-dst_start_port': '0.0',
+ 'sctp-a-egress-dst_start_port': '0.0',
+ 'fsb1_Internal2_mac': '00:80:37:0E:0B:12',
+ 'sctp-a-egress_ethertype': 'IPv4',
+ 'vlc_st_service_mode': 'in-network-nat',
+ 'sctp-a-ipv6-egress_ethertype': 'IPv4',
+ 'sctp-a-egress-src_end_port': '65535.0',
+ 'sctp-b-ipv6-egress_rule_application': 'any',
+ 'sctp-b-egress_action': 'pass',
+ 'sctp-a-ingress-src_subnet_prefix_len': '0.0',
+ 'sctp-b-ipv6-ingress-src_end_port': '65535.0',
+ 'sctp-b-name': 'epc-sctp-b-ipv4v6-sec-group',
+ 'fsb2_Internal1_mac': '00:80:37:0E:0D:12',
+ 'sctp-a-ipv6-ingress-src_start_port': '0.0',
+ 'sctp-b-ipv6-egress_ethertype': 'IPv4',
+ 'Internal1_net_cidr': '169.253.0.0',
+ 'sctp-a-egress_dst_subnet_prefix': '0.0.0.0',
+ 'fsb_flavor_name': 'nv.c20r64d1',
+ 'sctp_rule_protocol': '132',
+ 'sctp-b-ipv6-ingress_src_subnet_prefix_len': '0',
+ 'sctp-a-ipv6-ingress_rule_application': 'any',
+ 'sctp-a-IPv6_ethertype': 'IPv6',
+ 'vlc2_Internal1_mac': '00:80:37:0E:02:12',
+ 'vlc_st_virtualization_type': 'virtual-machine',
+ 'sctp-b-ingress-dst_start_port': '0.0',
+ 'sctp-b-ingress-dst_end_port': '65535.0',
+ 'sctp-a-ipv6-ingress-src_end_port': '65535.0',
+ 'sctp-a-display_name': 'epc-sctp-a-ipv4v6-sec-group',
+ 'sctp-b-ingress_rule_application': 'any',
+ 'int2_sec_group_name': 'int2-sec-group',
+ 'vlc_flavor_name': 'nd.c16r64d1',
+ 'sctp-b-ipv6-egress_src_addresses': 'local',
+ 'vlc_st_interface_type_int1': 'other1',
+ 'sctp-b-egress-src_end_port': '65535.0',
+ 'sctp-a-ipv6-egress-dst_start_port': '0',
+ 'vlc_st_interface_type_int2': 'other2',
+ 'sctp-a-ipv6-egress_rule_protocol': 'any',
+ 'Internal2_shared': 'false',
+ 'sctp-a-ipv6-egress_dst_subnet_prefix_len': '0',
+ 'Internal2_rpf': 'disable',
+ 'vlc1_Internal1_mac': '00:80:37:0E:01:12',
+ 'sctp-b-ipv6-egress_src_end_port': '65535',
+ 'sctp-a-ipv6-egress_src_addresses': 'local',
+ 'sctp-a-ingress-dst_end_port': '65535.0',
+ 'sctp-a-ipv6-egress_src_end_port': '65535',
+ 'Internal1_forwarding_mode': 'l2',
+ 'Internal2_dhcp': 'false',
+ 'sctp-a-dst_subnet_prefix_v6': '::',
+ 'pxe_image_name': 'MME_PXE-Boot_16ACP04_GA.qcow2',
+ 'vlc_st_interface_type_gtp': 'other0',
+ 'ncb1_Internal1_mac': '00:80:37:0E:09:12',
+ 'sctp-b-src_subnet_prefix_v6': '::',
+ 'sctp-a-egress_dst_subnet_prefix_len': '0.0',
+ 'int1_sec_group_name': 'int1-sec-group',
+ 'Internal1_dhcp': 'false',
+ 'sctp-a-ipv6-egress_dst_end_port': '65535',
+ 'Internal2_forwarding_mode': 'l2',
+ 'fsb2_Internal2_mac': '00:80:37:0E:0D:12',
+ 'sctp-b-egress_dst_subnet_prefix': '0.0.0.0',
+ 'Internal1_net_cidr_len': '17',
+ 'gpb2_Internal1_mac': '00:80:37:0E:02:22',
+ 'sctp-b-ingress-src_subnet_prefix_len': '0.0',
+ 'sctp-a-ingress_dst_addresses': 'local',
+ 'sctp-a-egress_action': 'pass',
+ 'fsb_volume_type_0': 'SF-Default-SSD',
+ 'ncb2_Internal2_mac': '00:80:37:0E:0F:12',
+ 'vlc_st_interface_type_sctp_a': 'left',
+ 'vlc_st_interface_type_sctp_b': 'right',
+ 'sctp-a-src_subnet_prefix_v6': '::',
+ 'vlc_st_version': '2',
+ 'sctp-b-egress_ethertype': 'IPv4',
+ 'sctp-a-ingress_rule_application': 'any',
+ 'gpb1_Internal2_mac': '00:80:37:0E:01:22',
+ 'instance_ip_family_v6': 'v6',
+ 'sctp-a-ipv6-egress_src_start_port': '0',
+ 'sctp-b-ingress-src_start_port': '0.0',
+ 'sctp-b-ingress_dst_addresses': 'local',
+ 'fsb1_Internal1_mac': '00:80:37:0E:0B:12',
+ 'vlc_st_interface_type_oam': 'management',
+ 'multi_stage_design': 'false',
+ 'oam_sec_group_name': 'oam-sec-group',
+ 'Internal2_net_gateway': '169.255.0.3',
+ 'sctp-a-ipv6-ingress-dst_end_port': '65535',
+ 'sctp-b-ipv6-egress-dst_start_port': '0',
+ 'Internal1_net_gateway': '169.253.0.3',
+ 'sctp-b-ipv6-egress_rule_protocol': 'any',
+ 'gtp_sec_group_name': 'gtp-sec-group',
+ 'sctp-a-ipv6-egress_dst_subnet_prefix': '0.0.0.0',
+ 'sctp-b-ipv6-egress_dst_subnet_prefix_len': '0',
+ 'sctp-a-ipv6-ingress_dst_addresses': 'local',
+ 'sctp-a-egress_rule_protocol': 'icmp',
+ 'sctp-b-ipv6-egress_action': 'pass',
+ 'sctp-a-ipv6-egress_action': 'pass',
+ 'Internal1_shared': 'false',
+ 'sctp-b-ipv6-ingress_rule_protocol': 'any',
+ 'Internal2_net_cidr_len': '17',
+ 'sctp-a-name': 'epc-sctp-a-ipv4v6-sec-group',
+ 'sctp-a-ingress-src_end_port': '65535.0',
+ 'sctp-b-ipv6-ingress_src_subnet_prefix': '0.0.0.0',
+ 'sctp-a-egress-dst_end_port': '65535.0',
+ 'sctp-a-ingress_action': 'pass',
+ 'sctp-b-egress_rule_protocol': 'icmp',
+ 'sctp-b-ipv6-ingress_action': 'pass',
+ 'vlc_st_service_type': 'firewall',
+ 'sctp-b-ipv6-egress_dst_end_port': '65535',
+ 'sctp-b-ipv6-ingress-dst_start_port': '0',
+ 'vlc2_Internal2_mac': '00:80:37:0E:02:12',
+ 'vlc_st_availability_zone': 'true',
+ 'fsb_volume_image_name_1': 'MME_FSB2_16ACP04_GA.qcow2',
+ 'sctp-b-ingress-src_subnet_prefix': '0.0.0.0',
+ 'sctp-a-ipv6-ingress_src_subnet_prefix_len': '0',
+ 'Internal1_allow_transit': 'true',
+ 'gpb_flavor_name': 'nv.c20r64d1',
+ 'availability_zone_max_count': '1',
+ 'fsb_volume_image_name_0': 'MME_FSB1_16ACP04_GA.qcow2',
+ 'sctp-b-ipv6-ingress_dst_addresses': 'local',
+ 'sctp-b-ipv6-egress_dst_subnet_prefix': '0.0.0.0',
+ 'sctp-b-ipv6-ingress_ethertype': 'IPv4',
+ 'vlc1_Internal2_mac': '00:80:37:0E:01:12',
+ 'sctp-a-ingress-src_subnet_prefix': '0.0.0.0',
+ 'sctp-a-ipv6-ingress_action': 'pass',
+ 'Internal1_rpf': 'disable',
+ 'sctp-b-ingress_ethertype': 'IPv4',
+ 'sctp-b-egress_rule_application': 'any',
+ 'sctp-b-ingress-src_end_port': '65535.0',
+ 'sctp-a-ipv6-ingress_rule_protocol': 'any',
+ 'sctp-a-ingress-src_start_port': '0.0',
+ 'sctp-b-egress-dst_end_port': '65535.0'
+ },
+ 'type': 'VF',
+ 'modelCustomizationName': 'VF_vMee 0',
+ 'vfModules': {
+ 'vf_vmee0..VfVmee..vmme_vlc..module-1': {
+ 'uuid': '522159d5-d6e0-4c2a-aa44-5a542a12a830',
+ 'invariantUuid': '98a7c88b-b577-476a-90e4-e25a5871e02b',
+ 'customizationUuid': '55b1be94-671a-403e-a26c-667e9c47d091',
+ 'description': null,
+ 'name': 'VfVmee..vmme_vlc..module-1',
+ 'version': '2',
+ 'modelCustomizationName': 'VfVmee..vmme_vlc..module-1',
+ 'properties': {'minCountInstances': 0, 'maxCountInstances': null, 'initialCount': 0},
+ 'commands': {},
+ 'volumeGroupAllowed': false
+ },
+ 'vf_vmee0..VfVmee..vmme_gpb..module-2': {
+ 'uuid': '41708296-e443-4c71-953f-d9a010f059e1',
+ 'invariantUuid': '1cca90b8-3490-495e-87da-3f3e4c57d5b9',
+ 'customizationUuid': '6add59e0-7fe1-4bc4-af48-f8812422ae7c',
+ 'description': null,
+ 'name': 'VfVmee..vmme_gpb..module-2',
+ 'version': '2',
+ 'modelCustomizationName': 'VfVmee..vmme_gpb..module-2',
+ 'properties': {'minCountInstances': 0, 'maxCountInstances': null, 'initialCount': 0},
+ 'commands': {},
+ 'volumeGroupAllowed': false
+ },
+ 'vf_vmee0..VfVmee..base_vmme..module-0': {
+ 'uuid': 'a27f5cfc-7f12-4f99-af08-0af9c3885c87',
+ 'invariantUuid': 'a6f9e51a-2b35-416a-ae15-15e58d61f36d',
+ 'customizationUuid': 'f8c040f1-7e51-4a11-aca8-acf256cfd861',
+ 'description': null,
+ 'name': 'VfVmee..base_vmme..module-0',
+ 'version': '2',
+ 'modelCustomizationName': 'VfVmee..base_vmme..module-0',
+ 'properties': {'minCountInstances': 1, 'maxCountInstances': 1, 'initialCount': 1},
+ 'commands': {},
+ 'volumeGroupAllowed': true
+ }
+ },
+ 'volumeGroups': {
+ 'vf_vmee0..VfVmee..base_vmme..module-0': {
+ 'uuid': 'a27f5cfc-7f12-4f99-af08-0af9c3885c87',
+ 'invariantUuid': 'a6f9e51a-2b35-416a-ae15-15e58d61f36d',
+ 'customizationUuid': 'f8c040f1-7e51-4a11-aca8-acf256cfd861',
+ 'description': null,
+ 'name': 'VfVmee..base_vmme..module-0',
+ 'version': '2',
+ 'modelCustomizationName': 'VfVmee..base_vmme..module-0',
+ 'properties': {'minCountInstances': 1, 'maxCountInstances': 1, 'initialCount': 1}
+ }
+ }
+ }
+ },
+ 'networks': {
+ 'ExtVL 0': {
+ 'uuid': 'ddc3f20c-08b5-40fd-af72-c6d14636b986',
+ 'invariantUuid': '379f816b-a7aa-422f-be30-17114ff50b7c',
+ 'description': 'ECOMP generic virtual link (network) base type for all other service-level and global networks',
+ 'name': 'ExtVL',
+ 'version': '37.0',
+ 'customizationUuid': '94fdd893-4a36-4d70-b16a-ec29c54c184f',
+ 'inputs': {},
+ 'commands': {},
+ 'properties': {
+ 'network_assignments': '{is_external_network=false, ipv4_subnet_default_assignment={min_subnets_count=1}, ecomp_generated_network_assignment=false, ipv6_subnet_default_assignment={min_subnets_count=1}}',
+ 'exVL_naming': '{ecomp_generated_naming=true}',
+ 'network_flows': '{is_network_policy=false, is_bound_to_vpn=false}',
+ 'network_homing': '{ecomp_selected_instance_node_target=false}'
+ },
+ 'type': 'VL',
+ 'modelCustomizationName': 'ExtVL 0'
+ }
+ },
+ 'configurations': {
+ 'Port Mirroring Configuration By Policy 0': {
+ 'uuid': 'b4398538-e89d-4f13-b33d-ca323434ba50',
+ 'invariantUuid': '6ef0ca40-f366-4897-951f-abd65d25f6f7',
+ 'description': 'A port mirroring configuration by policy object',
+ 'name': 'Port Mirroring Configuration By Policy',
+ 'version': '27.0',
+ 'customizationUuid': '3c3b7b8d-8669-4b3b-8664-61970041fad2',
+ 'inputs': {},
+ 'commands': {},
+ 'properties': {},
+ 'type': 'Configuration',
+ 'modelCustomizationName': 'Port Mirroring Configuration By Policy 0',
+ 'sourceNodes': [],
+ 'collectorNodes': null,
+ 'configurationByPolicy': false
+ }
+ },
+ 'serviceProxies': {},
+ 'vfModules': {
+ 'vf_vmee0..VfVmee..vmme_vlc..module-1': {
+ 'uuid': '522159d5-d6e0-4c2a-aa44-5a542a12a830',
+ 'invariantUuid': '98a7c88b-b577-476a-90e4-e25a5871e02b',
+ 'customizationUuid': '55b1be94-671a-403e-a26c-667e9c47d091',
+ 'description': null,
+ 'name': 'VfVmee..vmme_vlc..module-1',
+ 'version': '2',
+ 'modelCustomizationName': 'VfVmee..vmme_vlc..module-1',
+ 'properties': {'minCountInstances': 0, 'maxCountInstances': null, 'initialCount': 0},
+ 'commands': {},
+ 'volumeGroupAllowed': false
+ },
+ 'vf_vmee0..VfVmee..vmme_gpb..module-2': {
+ 'uuid': '41708296-e443-4c71-953f-d9a010f059e1',
+ 'invariantUuid': '1cca90b8-3490-495e-87da-3f3e4c57d5b9',
+ 'customizationUuid': '6add59e0-7fe1-4bc4-af48-f8812422ae7c',
+ 'description': null,
+ 'name': 'VfVmee..vmme_gpb..module-2',
+ 'version': '2',
+ 'modelCustomizationName': 'VfVmee..vmme_gpb..module-2',
+ 'properties': {'minCountInstances': 0, 'maxCountInstances': null, 'initialCount': 0},
+ 'commands': {},
+ 'volumeGroupAllowed': false
+ },
+ 'vf_vmee0..VfVmee..base_vmme..module-0': {
+ 'uuid': 'a27f5cfc-7f12-4f99-af08-0af9c3885c87',
+ 'invariantUuid': 'a6f9e51a-2b35-416a-ae15-15e58d61f36d',
+ 'customizationUuid': 'f8c040f1-7e51-4a11-aca8-acf256cfd861',
+ 'description': null,
+ 'name': 'VfVmee..base_vmme..module-0',
+ 'version': '2',
+ 'modelCustomizationName': 'VfVmee..base_vmme..module-0',
+ 'properties': {'minCountInstances': 1, 'maxCountInstances': 1, 'initialCount': 1},
+ 'commands': {},
+ 'volumeGroupAllowed': true
+ }
+ },
+ 'volumeGroups': {
+ 'vf_vmee0..VfVmee..base_vmme..module-0': {
+ 'uuid': 'a27f5cfc-7f12-4f99-af08-0af9c3885c87',
+ 'invariantUuid': 'a6f9e51a-2b35-416a-ae15-15e58d61f36d',
+ 'customizationUuid': 'f8c040f1-7e51-4a11-aca8-acf256cfd861',
+ 'description': null,
+ 'name': 'VfVmee..base_vmme..module-0',
+ 'version': '2',
+ 'modelCustomizationName': 'VfVmee..base_vmme..module-0',
+ 'properties': {'minCountInstances': 1, 'maxCountInstances': 1, 'initialCount': 1}
+ }
+ },
+ 'pnfs': {}
+ }
+ }
+ ));
+ }
+
+});
diff --git a/vid-webpack-master/src/app/drawingBoard/available-models-tree/available-models-tree.service.ts b/vid-webpack-master/src/app/drawingBoard/available-models-tree/available-models-tree.service.ts
new file mode 100644
index 000000000..57dc4b409
--- /dev/null
+++ b/vid-webpack-master/src/app/drawingBoard/available-models-tree/available-models-tree.service.ts
@@ -0,0 +1,36 @@
+import {Injectable} from '@angular/core';
+import * as _ from "lodash";
+import {ServicePlanningService} from "../../services/service-planning.service";
+
+@Injectable()
+export class AvailableModelsTreeService {
+ constructor(private _servicePlanningService: ServicePlanningService) {
+ }
+
+ shouldShowAddIcon(node: any, serviceHierarchy: any, serviceModelId: string, currentNodeCount: number): boolean {
+ let maxNodes: number = 1;
+ if (node.data.children !== null && node.data.children.length == 0) {
+ let vnfModules = serviceHierarchy[serviceModelId].vfModules;
+ if (vnfModules[node.data.name]) {
+ maxNodes = vnfModules[node.data.name].properties.maxCountInstances || 1;
+ }
+ }
+ return !node.data.disabled && currentNodeCount < maxNodes
+ }
+
+ shouldOpenDialog(type: string, dynamicInputs: any, userProvidedNaming: boolean): boolean {
+ if (userProvidedNaming || this._servicePlanningService.requiredFields[type].length > 0) {
+ return true;
+ }
+
+ if (dynamicInputs) {
+ for(let input of dynamicInputs) {
+ if (input.isRequired && _.isEmpty(input.value)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+}
diff --git a/vid-webpack-master/src/app/drawingBoard/drawing-board-header/drawing-board-header.component.html b/vid-webpack-master/src/app/drawingBoard/drawing-board-header/drawing-board-header.component.html
new file mode 100644
index 000000000..7d0f7f456
--- /dev/null
+++ b/vid-webpack-master/src/app/drawingBoard/drawing-board-header/drawing-board-header.component.html
@@ -0,0 +1,33 @@
+<div class="drawing-board-header">
+ <div class="left-header">
+ <span [attr.data-tests-id]="'backBtn'" class="icon-back" (click)="closePage()"></span>
+ <span [attr.data-tests-id]="'serviceInstance'" class="service-instance-label">Service instance:</span>
+ <span [attr.data-tests-id]="'serviceName'" class="service-instance-name">{{serviceName}}</span>
+ <span class="quantity-container" style=" padding: 10px;font-size: 13px;" tooltip="Number of services to instantiate including all their objects as defined below">
+ <span [attr.data-tests-id]="'quantityLabel'" class="quantity-label" >Scale Times:</span>
+ <span [attr.data-tests-id]="'servicesQuantity'" class="quantity" style="font-family: OpenSans-Semibold;font-size: 14px;"> {{numServicesToDeploy}} </span>
+ </span>
+ <span class="service-instance-label">status:</span>
+ <span [attr.data-tests-id]="'serviceStatus'" class="status">{{status}}</span>
+ </div>
+ <div class="right-header">
+ <span class="menu-container">
+ <span [attr.data-tests-id]="'openMenuBtn'" class="icon-browse" (click)="onContextMenu($event)"></span>
+ <context-menu>
+ <ng-template contextMenuItem (execute)="editService()">
+ <div [attr.data-tests-id]="'context-menu-header-edit-item'">
+ <span class="icon-edit"></span>
+ Edit
+ </div>
+ </ng-template>
+ <ng-template contextMenuItem (execute)="closePage()">
+ <div [attr.data-tests-id]="'context-menu-header-delete-item'">
+ <span class="icon-trash"></span>
+ Delete
+ </div>
+ </ng-template>
+ </context-menu>
+ </span>
+ <button [disabled]="false" [attr.data-tests-id]="'deployBtn'" (click)="deployMacroservice()" class="deploy-btn">DEPLOY</button>
+ </div>
+</div>
diff --git a/vid-webpack-master/src/app/drawingBoard/drawing-board-header/drawing-board-header.component.scss b/vid-webpack-master/src/app/drawingBoard/drawing-board-header/drawing-board-header.component.scss
new file mode 100644
index 000000000..29b7711bc
--- /dev/null
+++ b/vid-webpack-master/src/app/drawingBoard/drawing-board-header/drawing-board-header.component.scss
@@ -0,0 +1,95 @@
+.drawing-board-header {
+ height: 56px;
+ margin-bottom: 4px;
+ position: relative;
+ font-family: OpenSans-Regular;
+ display: flex;
+ justify-content: space-between;
+ font-size: 14px;
+ box-shadow: 2px 2px 6px #D2D2D2;
+ color: #191919;
+ [class^="icon-"] {
+ height: 56px;
+ width: 56px;
+ display: flex;
+ align-items: center;
+ text-align: center;
+ color: #5A5A5A;
+ cursor: pointer;
+ &:before {
+ font-size: 18px;
+ width: 100%;
+ }
+ &:hover:before {
+ color: #009FDB;
+ }
+ }
+ .left-header {
+ display: flex;
+ align-items: center;
+ .icon-back {
+ border-right: 1px solid #EAEAEA;
+ &:before {
+ content: "\e906";
+ font-size: 24px;
+ }
+ }
+ .service-instance-label {
+ padding: 0 5px;
+ font-family: OpenSans-Regular;
+ font-size: 13px;
+ color: #191919;
+ }
+ .service-instance-name {
+ padding-right: 20px;
+ color: #191919;
+ font-family: OpenSans-Semibold;
+ background-color: white;
+ font-size: 16px
+ }
+ .status {
+ font-family: OpenSans-Semibold;
+ line-height: 14px;
+ font-size: 14px;
+ }
+ }
+ .right-header {
+ display: flex;
+ align-items: center;
+ .quantity-container {
+ .quantity-label {
+ padding-left: 10px;
+ font-family: OpenSans-Semibold;
+ font-size: 12px;
+ }
+ .quantity {
+ padding: 5px 10px 5px 0;
+ font-family: OpenSans-Semibold;
+ font-size: 18px;
+ }
+ }
+ [class^="icon-"] {
+ border-left: 1px solid #EAEAEA;
+ }
+ .menu-container {
+ height: 100%;
+ display: flex;
+ background: none;
+ border: none;
+ padding: 0;
+ outline: none;
+ }
+ .icon-browse:before {
+ content: '\e924';
+ display: inline-block;
+ font-size: 24px;
+ }
+ .deploy-btn {
+ color: #FFFFFF ;
+ background: #009fdb;
+ width: 128px;
+ height: 100%;
+ border: none;
+ }
+ }
+}
diff --git a/vid-webpack-master/src/app/drawingBoard/drawing-board-header/drawing-board-header.component.ts b/vid-webpack-master/src/app/drawingBoard/drawing-board-header/drawing-board-header.component.ts
new file mode 100644
index 000000000..38284e214
--- /dev/null
+++ b/vid-webpack-master/src/app/drawingBoard/drawing-board-header/drawing-board-header.component.ts
@@ -0,0 +1,119 @@
+import {Component, ViewChild} from '@angular/core';
+import {ContextMenuComponent, ContextMenuService} from 'ngx-contextmenu';
+import {DialogService} from 'ng2-bootstrap-modal';
+import {ServicePopupComponent} from '../../components/service-popup/service-popup.component';
+import {MsoService} from '../../services/msoService/mso.service'
+import * as _ from 'lodash';
+import {ActivatedRoute} from '@angular/router';
+import {ServiceInstance} from "../../shared/models/serviceInstance";
+import {OwningEntity} from "../../shared/models/owningEntity";
+import {MessageBoxData, ModalSize, ModalType} from "../../shared/components/messageBox/messageBox.data";
+import {MessageBoxService} from "../../shared/components/messageBox/messageBox.service";
+import {NgRedux} from "@angular-redux/store";
+import {AppState} from "../../store/reducers";
+import {IframeService} from "../../shared/utils/iframe.service";
+
+@Component({
+ selector: 'drawing-board-header',
+ providers: [MsoService],
+ templateUrl: './drawing-board-header.component.html',
+ styleUrls: ['./drawing-board-header.component.scss']
+})
+
+export class DrawingBoardHeader {
+ serviceName: string;
+ numServicesToDeploy: number;
+ status: string = 'Designing a new service';
+ serviceModelId: string;
+ parentElementClassName = 'content';
+
+ constructor(private _contextMenuService: ContextMenuService, private dialogService: DialogService,
+ private _iframeService : IframeService,
+ private route: ActivatedRoute, private msoService: MsoService,
+ private store: NgRedux<AppState>) {
+ this.route
+ .queryParams
+ .subscribe(params => {
+ this.serviceModelId = params['serviceModelId'];
+ if (_.has(this.store.getState().service.serviceHierarchy, this.serviceModelId)) {
+ this.setValuesFromStore();
+ this.store.subscribe(() => {
+ this.setValuesFromStore();
+ });
+ }
+ });
+ }
+
+
+ @ViewChild(ContextMenuComponent) public contextMenu: ContextMenuComponent;
+
+ public onContextMenu($event: MouseEvent, item: any): void {
+ this._contextMenuService.show.next({
+ contextMenu: this.contextMenu,
+ event: $event,
+ item: item,
+ });
+ $event.preventDefault();
+ $event.stopPropagation();
+ }
+
+ private setValuesFromStore() {
+ const serviceInstance = this.store.getState().service.serviceInstance[this.serviceModelId];
+ this.numServicesToDeploy = serviceInstance.bulkSize;
+ this.serviceName = serviceInstance.instanceName || '<Automatically Assigned>';
+
+ }
+
+ public editService(): void {
+ this._iframeService.addClassOpenModal(this.parentElementClassName);
+ this.dialogService.addDialog(ServicePopupComponent, {})
+
+ }
+
+
+ extractOwningEntityNameAccordingtoId(id:String): string {
+ let owningEntityName;
+ _.forEach(this.store.getState().service.categoryParameters.owningEntityList,function(owningEntity: OwningEntity) {
+ if (owningEntity.id === id) {
+ owningEntityName = owningEntity.name;
+
+ }})
+
+ return owningEntityName;
+ }
+
+ extractServiceFields(): any {
+ let instanceFields : ServiceInstance;
+ instanceFields = this.store.getState().service.serviceInstance[Object.keys(this.store.getState().service.serviceInstance)[0]];
+ instanceFields.subscriberName = this.store.getState().service.subscribers.find(sub => sub.id === instanceFields.globalSubscriberId).name;
+ instanceFields.owningEntityName = this.extractOwningEntityNameAccordingtoId(instanceFields.owningEntityId);
+ return instanceFields;
+ }
+
+ public deployMacroservice(): void {
+ var instanceFields = this.extractServiceFields();
+ instanceFields.rollbackOnFailure = instanceFields.rollbackOnFailure === 'true';
+ this.msoService.submitMsoTask(instanceFields).subscribe((result) => {
+ window.parent.postMessage("navigateToInstantiationStatus", '*');
+ })
+ }
+
+ closePage() {
+ let messageBoxData : MessageBoxData = new MessageBoxData(
+ "Delete Instantiation", // modal title
+ "You are about to stop the instantiation process of this service. \nAll data will be lost. Are you sure you want to stop?",
+
+ ModalType.alert,
+ ModalSize.medium,
+ [
+ {text:"Stop Instantiation", size:"large", callback: this.navigate.bind(this), closeModal:true},
+ {text:"Cancel", size:"medium", closeModal:true}
+ ]);
+
+ MessageBoxService.openModal.next(messageBoxData);
+ }
+
+ navigate(){
+ window.parent.postMessage("navigateTo", "*");
+ }
+}
diff --git a/vid-webpack-master/src/app/drawingBoard/drawing-board-header/tmp_instansiate_request.ts b/vid-webpack-master/src/app/drawingBoard/drawing-board-header/tmp_instansiate_request.ts
new file mode 100644
index 000000000..7accc3a9c
--- /dev/null
+++ b/vid-webpack-master/src/app/drawingBoard/drawing-board-header/tmp_instansiate_request.ts
@@ -0,0 +1,52 @@
+export default
+ {
+ "modelInfo": {
+ "modelType": "service",
+ "modelInvariantId": "5d48acb5-097d-4982-aeb2-f4a3bd87d31b",
+ "modelVersionId": "3c40d244-808e-42ca-b09a-256d83d19d0a",
+ "modelName": "MOW AVPN vMX BV vPE 1 Service",
+ "modelVersion": "10.0"
+ },
+ "owningEntityId": "038d99af-0427-42c2-9d15-971b99b9b489",
+ "owningEntityName": "PACKET CORE",
+ "projectName": "{some project name}",
+ "globalSubscriberId": "{some subscriber id}",
+ "productFamilyId": "a9a77d5a-123e-4ca2-9eb9-0b015d2ee0fb",
+ "instanceName": "vPE_Service",
+ "subscriptionServiceType": "VMX",
+ "lcpCloudRegionId": "mdt1",
+ "tenantId": "88a6ca3ee0394ade9403f075db23167e",
+ "vnfs": [
+ {
+ "modelInfo": {
+ "modelName": "2016-73_MOW-AVPN-vPE-BV-L",
+ "modelVersionId": "7f40c192-f63c-463e-ba94-286933b895f8",
+ "modelCustomizationName": "2016-73_MOW-AVPN-vPE-BV-L 0",
+ "modelCustomizationId": "ab153b6e-c364-44c0-bef6-1f2982117f04"
+ },
+ "lcpCloudRegionId": "mdt1",
+ "tenantId": "88a6ca3ee0394ade9403f075db23167e",
+ "platformName": "test",
+ "productFamilyId": "a9a77d5a-123e-4ca2-9eb9-0b015d2ee0fb",
+ "instanceName": "vmxnjr001",
+ "instanceParams": [],
+ "vfModules": [
+ {
+ "modelInfo": {
+ "modelType": "vfModule",
+ "modelName": "201673MowAvpnVpeBvL..AVPN_base_vPE_BV..module-0",
+ "modelVersionId": "4c75f813-fa91-45a4-89d0-790ff5f1ae79",
+ "modelCustomizationId": "a25e8e8c-58b8-4eec-810c-97dcc1f5cb7f"
+ },
+ "instanceName": "vmxnjr001_AVPN_base_vPE_BV_base_001",
+ "instanceParams": [
+ {
+ "vmx_int_net_len": "24"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+
diff --git a/vid-webpack-master/src/app/drawingBoard/drawing-board-tree/drawing-board-tree.component.ts b/vid-webpack-master/src/app/drawingBoard/drawing-board-tree/drawing-board-tree.component.ts
new file mode 100644
index 000000000..6b717a930
--- /dev/null
+++ b/vid-webpack-master/src/app/drawingBoard/drawing-board-tree/drawing-board-tree.component.ts
@@ -0,0 +1,133 @@
+import {AfterViewInit, Component, EventEmitter, OnInit, Output, ViewChild} from '@angular/core';
+import { ContextMenuService } from 'ngx-contextmenu';
+import { Constants } from '../../shared/utils/constants';
+import {ServicePlanningService} from "../../services/service-planning.service";
+import {ITreeNode} from "angular-tree-component/dist/defs/api";
+import {ITreeOptions, TreeComponent} from "angular-tree-component";
+import {VnfPopupComponent} from "../../components/vnf-popup/vnf-popup.components";
+import {DialogService} from "ng2-bootstrap-modal";
+import {ActivatedRoute} from "@angular/router";
+import {NgRedux} from "@angular-redux/store";
+import {AppState} from "../../store/reducers";
+import { MessageBoxData, ModalSize, ModalType } from '../../shared/components/messageBox/messageBox.data';
+import { MessageBoxService } from '../../shared/components/messageBox/messageBox.service';
+import { deleteVnfInstance, deleteVfModuleInstance } from '../../service.actions';
+import { isNullOrUndefined } from 'util';
+import {IframeService} from "../../shared/utils/iframe.service";
+
+
+@Component({
+ selector: 'drawing-board-tree',
+ templateUrl: './drawing-board-tree.html',
+ styleUrls : ['./drawing-board-tree.scss']
+})
+
+
+export class DrawingBoardTreeComponent implements OnInit, AfterViewInit {
+ constructor(private _contextMenuService: ContextMenuService,
+ private _servicePlanningService: ServicePlanningService,
+ private _iframeService : IframeService,
+ private dialogService: DialogService,
+ private store: NgRedux<AppState>,
+ private route: ActivatedRoute) {
+ this.route
+ .queryParams
+ .subscribe(params => {
+ this.serviceModelId = params['serviceModelId'];
+ });
+ }
+
+ @Output()
+ highlightNode : EventEmitter<number> = new EventEmitter<number>();
+
+ @ViewChild('tree') tree: TreeComponent;
+ missingDataTooltip: string = Constants.Error.MISSING_VNF_DETAILS;
+ currentNode: ITreeNode = null; //
+ nodes = [];
+ serviceModelId: string;
+ options: ITreeOptions = {
+ nodeHeight: 45,
+ dropSlotHeight: 1
+ };
+ parentElementClassName = 'content';
+
+ ngOnInit(): void {
+ this.store.subscribe(() => {this.updateTree()});
+ this.updateTree()
+ }
+
+ updateTree() {
+ const serviceInstance = this.store.getState().service.serviceInstance[this.serviceModelId];
+ this.nodes = this._servicePlanningService.convertServiceInstanceToTreeData(serviceInstance, this.serviceModelId);
+ }
+
+ ngAfterViewInit():void {
+ // Expand drawing tree on init.
+ this.tree.treeModel.expandAll();
+ }
+
+ public onContextMenu($event: MouseEvent, node: ITreeNode): void {
+ this.currentNode = node;
+ node.focus();
+ node.setActiveAndVisible(false);
+ this.selectNode(node);
+ this._contextMenuService.show.next({
+ event: <any>$event,
+ item: node,
+ });
+ $event.preventDefault();
+ $event.stopPropagation();
+ }
+
+ public editItem(node: ITreeNode): void {
+ node = this.currentNode;
+ this._iframeService.addClassOpenModal(this.parentElementClassName);
+ this.dialogService.addDialog(VnfPopupComponent, {
+ serviceModelId: this.serviceModelId,
+ modelName: node.data.modelName,
+ modelType: node.data.type,
+ parentModelName: node.parent.data.modelName,
+ isNewVfModule : false
+ })
+ }
+
+ public deleteItem(node: ITreeNode): void {
+ if(this.currentNode.data.type === 'VF'){
+ if(!isNullOrUndefined(this.currentNode.data.children) && this.currentNode.data.children.length === 0){
+ this.store.dispatch(deleteVnfInstance(this.currentNode.data.modelName, this.serviceModelId));
+ }else {
+ let messageBoxData : MessageBoxData = new MessageBoxData(
+ "Remove VNF", // modal title
+ "You are about to remove this VNF and all its children from this service. Are you sure you want to remove it?",
+
+ ModalType.alert,
+ ModalSize.medium,
+ [
+ {text:"Remove VNF", size:"large", callback: this.removeVnf.bind(this), closeModal:true},
+ {text:"Don’t Remove", size:"medium", closeModal:true}
+ ]);
+
+ MessageBoxService.openModal.next(messageBoxData);
+ }
+ }else {
+ this.store.dispatch(deleteVfModuleInstance(this.currentNode.data.modelName, this.serviceModelId, node.parent.data.modelName));
+ }
+ }
+
+ removeVnf() {
+ this.store.dispatch(deleteVnfInstance(this.currentNode.data.modelName, this.serviceModelId));
+ }
+
+ public selectNode(node: ITreeNode): void {
+ node.expand();
+ this.highlightNode.emit(node.data.modelId);
+ }
+
+ isDataMissing(node: ITreeNode) {
+ //todo: currently not showing the alert icon. will be implemented in upcoming story.
+ return false;
+ }
+
+}
+
+
diff --git a/vid-webpack-master/src/app/drawingBoard/drawing-board-tree/drawing-board-tree.html b/vid-webpack-master/src/app/drawingBoard/drawing-board-tree/drawing-board-tree.html
new file mode 100644
index 000000000..c4061db9e
--- /dev/null
+++ b/vid-webpack-master/src/app/drawingBoard/drawing-board-tree/drawing-board-tree.html
@@ -0,0 +1,42 @@
+<div class="drawing-board-tree">
+ <div *ngIf="nodes?.length == 0" style="text-align: center; margin-top: 50px;">
+ <no-content-message-and-icon class="span-over"
+ data-title="Please add objects (VNFs, network, modules etc.) from the left tree to design the service instance"
+ subtitle="Once done, click Deploy to start instantiation"
+ iconPath="./assets/img/UPLOAD.svg"
+ iconClass="upload-icon-service-planing"></no-content-message-and-icon>
+ </div>
+ <tree-root [attr.data-tests-id]="'drawing-board-tree'" #tree [nodes]="nodes" [options]="options" id="drawing-board-tree">
+ <ng-template #treeNodeTemplate let-node let-index="index">
+ <div [attr.data-tests-id]="'node-'+node.data.modelId +'-' +node.data.modelName" (click)="selectNode(node)">
+ <div class="model-info">
+ <span>
+ <span class="property-name">{{node.data.type}}{{node.data.name ? ': ': ''}}<span class="auto-name">{{node.data.name? node.data.name: ''}}</span></span>
+ </span>
+ </div>
+ <div class="model-actions">
+ <span class="icon-browse" [attr.data-tests-id]="'node-'+node.data.modelId +'-' +node.data.modelName+'-menu-btn'" (click)="onContextMenu($event, node)" >
+ <context-menu>
+ <ng-template contextMenuItem (execute)="editItem(node)">
+ <div [attr.data-tests-id]="'context-menu-item'">
+ <span class="icon-edit"></span>
+ Edit
+ </div>
+ </ng-template>
+ <ng-template contextMenuItem (execute)="deleteItem(node)">
+ <div>
+ <span class="icon-trash"></span>
+ Remove
+ </div>
+ </ng-template>
+ </context-menu>
+ </span>
+ <span *ngIf="isDataMissing(node)" class="icon-alert" tooltip="{{ missingDataTooltip }}" tooltipPlacement="left" [attr.data-tests-id]="'node-'+node.data.modelId +'-' +node.data.modelName+'-alert-icon'"></span>
+ </div>
+ </div>
+
+ </ng-template>
+ </tree-root>
+</div>
+
+
diff --git a/vid-webpack-master/src/app/drawingBoard/drawing-board-tree/drawing-board-tree.scss b/vid-webpack-master/src/app/drawingBoard/drawing-board-tree/drawing-board-tree.scss
new file mode 100644
index 000000000..fed9ead10
--- /dev/null
+++ b/vid-webpack-master/src/app/drawingBoard/drawing-board-tree/drawing-board-tree.scss
@@ -0,0 +1,274 @@
+@mixin highlight($background-color, $color) {
+ background: none;
+ padding: 0;
+ background-color: $background-color;
+ border: $color 1px solid;
+ color: $color;
+}
+@mixin highlight-toggle-children {
+ tree-node-expander {
+ .toggle-children-wrapper {
+ span.toggle-children {
+ @include highlight(white, #009FDB);
+ border-right: none;
+ }
+ }
+ }
+}
+
+@mixin highlight-tree-node-content {
+ tree-node-content {
+ > div {
+ .model-actions {
+ .icon-browse:before {
+ display: inline-block;
+ }
+ }
+ }
+ }
+}
+
+drawing-board-tree {
+
+ .toggle-children-wrapper.toggle-children-wrapper-expanded {
+ .toggle-children:before {
+ color: #009FDB;
+ }
+ }
+
+ overflow: auto;
+ flex: 1;
+ color: #5A5A5A;
+ line-height: 14px;
+ .drawing-board-tree {
+ width: 100%;
+ }
+ tree-viewport {
+ padding: 50px 3.5% 1% 6%;
+ tree-node {
+ tree-node-drop-slot {
+ .node-drop-slot {
+ display: none;
+ }
+ }
+ & .tree-node-focused,
+ & .tree-node-active {
+ & > tree-node-wrapper {
+ .node-wrapper {
+ @include highlight-toggle-children;
+ .node-content-wrapper-focused,
+ .node-content-wrapper-active
+ {
+ @include highlight(#E6F6FB, #009FDB);
+ .property-name {
+ color: #009FDB;
+ }
+ .auto-name {
+ font-family: OpenSans-Regular !important;
+ }
+ .icon-browse:before {
+ color: #5A5A5A;
+ }
+ @include highlight-tree-node-content;
+ }
+ }
+ }
+ }
+ & .tree-node-expanded {
+ > tree-node-wrapper .node-wrapper {
+ box-shadow: 0 0px 2px rgba(90,90,90,0.24);
+ }
+ }
+
+ .tree-node-active .tree-children {
+ border: 1px solid #009FDB;
+ padding: 20px;
+ }
+
+
+
+ .tree-node.tree-node-active.tree-node-expanded {
+ border: 1px solid #009FDB;
+ }
+
+ .tree-node-leaf .node-wrapper{
+ margin-left: -45px;
+ }
+
+ tree-node-wrapper {
+ .node-wrapper {
+ height: 45px;
+ &:hover {
+ @include highlight-toggle-children;
+ .node-content-wrapper {
+ @include highlight(#E6F6FB, #009FDB);
+ .property-name {
+ color: #009FDB;
+ }
+ .icon-browse:before {
+ color: #5A5A5A;
+ }
+ @include highlight-tree-node-content;
+ }
+ }
+ tree-node-expander {
+ font-family: 'icomoon' !important;
+ height: 100%;
+ .toggle-children-wrapper {
+ padding: 0;
+ display: block;
+ height: 100%;
+ span.toggle-children {
+ display: flex;
+ width: 45px;
+ padding: 0;
+ top: 0;
+ height: inherit;
+ background-image: none;
+ background-color: white;
+ border: 1px solid #D2D2D2;
+ border-right: none;
+ &:before {
+ content: "\e900";
+ font-size: 20px;
+ font-weight: 600;
+ text-align: center;
+ display: inline-block;
+ flex: auto;
+ align-self: center;
+ }
+ }
+ }
+ .toggle-children-wrapper-expanded {
+ span.toggle-children {
+ transform: none;
+ &:before {
+ content: "\e930";
+ }
+ }
+ }
+ .toggle-children-placeholder {
+ width:45px;
+ }
+ }
+ .node-content-wrapper {
+ padding: 0;
+ background: none;
+ box-shadow: none;
+ border-radius: 0;
+ border: 1px solid #D2D2D2;
+ height: 100%;
+ flex: 1;
+ tree-node-content {
+ > div {
+ height: 100%;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ .model-info {
+ flex: 1;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding-left: 8px;
+ > span {
+ flex: 1;
+ padding: 0 8px;
+ span:nth-child(2) {
+ display: block;
+ }
+ }
+ }
+ .model-actions {
+ display: flex;
+ align-items: center;
+ padding-right: 12px;
+ .icon-browse {
+ padding: 0;
+ width: 30px;
+ &:before {
+ content: "\e924";
+ font-size: 24px;
+ display: none;
+ }
+ &:hover:before {
+ color: #009FDB;
+ }
+ &:focus:before,
+ &:active:before {
+ color: #009FDB;
+ }
+ }
+
+ .icon-alert {
+ padding-left: 10px;
+ &:before {
+ content: "\e904";
+ font-size: 16px;
+ color: #ffb81c;
+ }
+ }
+ }
+ }
+ }
+ .property-name {
+ font-family: OpenSans-Semibold;
+ font-size: 12px;
+ line-height: 12px;
+ color: #191919;
+ text-transform: capitalize;
+ }
+ }
+
+
+ }
+ }
+ tree-node-children {
+ .tree-children {
+ padding: 20px;
+ .model-info span:first-child {
+ flex: 1.1 !important;
+ }
+ }
+ }
+ }
+ }
+}
+.cdk-overlay-pane.ngx-contextmenu {
+ ul.dropdown-menu {
+ width: 200px;
+ box-shadow: none;
+ padding: 0;
+ padding-top: 10px;
+ margin: 0;
+ border: 1px solid #D2D2D2;
+ border-top: 3px solid #009FDB;
+ box-shadow: 0 0px 2px rgba(90,90,90,0.24);
+ border-radius: 2px;
+ li {
+ height: 40px;
+ a {
+ font-family: OpenSans-Regular;
+ display: flex;
+ align-items: center;
+ height: 100%;
+ padding: 12px;
+ color: #5A5A5A;
+ &:hover {
+ background: #E6F6FB;
+ color: #009FDB;
+ }
+ span {
+ padding-right: 12px;
+ &.icon-edit:before {
+ content: '\e917';
+ }
+ &.icon-trash:before {
+ content: '\e937';
+ }
+ }
+ }
+ }
+ }
+}
+
diff --git a/vid-webpack-master/src/app/drawingBoard/drawingBoard.module.ts b/vid-webpack-master/src/app/drawingBoard/drawingBoard.module.ts
new file mode 100644
index 000000000..41efbe0e8
--- /dev/null
+++ b/vid-webpack-master/src/app/drawingBoard/drawingBoard.module.ts
@@ -0,0 +1,41 @@
+import { AvailableModelsTreeService } from './available-models-tree/available-models-tree.service';
+import { NgModule } from '@angular/core';
+import { HighlightPipe } from '../shared/pipes/highlight-filter.pipe';
+import { TreeModule } from 'angular-tree-component';
+import { BrowserModule } from '@angular/platform-browser';
+import { TooltipModule } from 'ngx-tooltip';
+import { AvailableModelsTreeComponent } from './available-models-tree/available-models-tree.component';
+import { ServicePlanningService } from '../services/service-planning.service';
+import { AaiService } from '../services/aaiService/aai.service';
+import { DrawingBoardTreeComponent } from './drawing-board-tree/drawing-board-tree.component';
+import { SharedModule } from '../shared/shared.module';
+import { ContextMenuModule, ContextMenuService } from 'ngx-contextmenu';
+import { CommonModule } from '@angular/common';
+import { DrawingBoardHeader } from './drawing-board-header/drawing-board-header.component';
+import { ServicePlanningComponent, ServicePlanningEmptyComponent } from './service-planning/service-planning.component';
+
+@NgModule({
+ imports: [
+ TreeModule,
+ BrowserModule,
+ ContextMenuModule,
+ TooltipModule,
+ CommonModule,
+ SharedModule.forRoot()],
+ providers: [
+ ServicePlanningService,
+ AaiService,
+ AvailableModelsTreeService ,
+ ContextMenuService,
+ ServicePlanningService],
+ declarations: [
+ AvailableModelsTreeComponent,
+ HighlightPipe,
+ DrawingBoardTreeComponent,
+ DrawingBoardHeader,
+ ServicePlanningComponent,
+ ServicePlanningEmptyComponent],
+ exports: [ AvailableModelsTreeComponent, DrawingBoardTreeComponent, DrawingBoardHeader]
+})
+
+export class DrawingBoardModule { }
diff --git a/vid-webpack-master/src/app/drawingBoard/service-planning/service-planning.component.html b/vid-webpack-master/src/app/drawingBoard/service-planning/service-planning.component.html
new file mode 100644
index 000000000..5b2f22d5f
--- /dev/null
+++ b/vid-webpack-master/src/app/drawingBoard/service-planning/service-planning.component.html
@@ -0,0 +1,13 @@
+<div class="service-planning-header">
+ <drawing-board-header></drawing-board-header>
+</div>
+<div class="service-planning-content row">
+ <available-models-tree class="left-side col-md-6" (highlightInstances)="highlightInstancesBySelectingNode($event)"></available-models-tree>
+ <!--<no-content-message-and-icon *ngIf="!isShowTree()" class="span-over"-->
+ <!--data-title="Please add objects (VNFs, network, modules etc.) from the left tree to design the service instance"-->
+ <!--subtitle="Once done, click Deploy to start instantiation"-->
+ <!--iconPath="./img/UPLOAD.svg"-->
+ <!--iconClass="upload-icon-service-planing"></no-content-message-and-icon>-->
+ <drawing-board-tree *ngIf="isShowTree()" class="span-over col-md-6" (highlightNode)="highlightNodeBySelectingInstance($event)"></drawing-board-tree>
+</div>
+
diff --git a/vid-webpack-master/src/app/drawingBoard/service-planning/service-planning.component.scss b/vid-webpack-master/src/app/drawingBoard/service-planning/service-planning.component.scss
new file mode 100644
index 000000000..69546a6c0
--- /dev/null
+++ b/vid-webpack-master/src/app/drawingBoard/service-planning/service-planning.component.scss
@@ -0,0 +1,16 @@
+
+.service-planning-content {
+ display: flex;
+ flex: 1;
+}
+
+.span-over {
+ display: flex;
+ flex: 1;
+}
+
+//css for the icon. :host ::ng-deep are needed for applying css to child component
+:host ::ng-deep .upload-icon-service-planing {
+ height: 117px;
+ margin-top: 32px;
+}
diff --git a/vid-webpack-master/src/app/drawingBoard/service-planning/service-planning.component.ts b/vid-webpack-master/src/app/drawingBoard/service-planning/service-planning.component.ts
new file mode 100644
index 000000000..1ce0e8100
--- /dev/null
+++ b/vid-webpack-master/src/app/drawingBoard/service-planning/service-planning.component.ts
@@ -0,0 +1,77 @@
+import {Component, ViewChild} from '@angular/core';
+import {DrawingBoardTreeComponent} from "../drawing-board-tree/drawing-board-tree.component";
+import {AvailableModelsTreeComponent} from "../available-models-tree/available-models-tree.component";
+import {ITreeNode} from "angular-tree-component/dist/defs/api";
+import {TreeComponent} from 'angular-tree-component';
+
+@Component({
+ selector: 'service-planning',
+ templateUrl: './service-planning.component.html',
+ styleUrls: ['./service-planning.component.scss']
+})
+
+export class ServicePlanningComponent {
+
+ @ViewChild(DrawingBoardTreeComponent) drawingModelTree;
+ @ViewChild(AvailableModelsTreeComponent) availableModelTree;
+
+ isShowTree(): boolean {
+ return true;
+ }
+
+ public highlightNodeBySelectingInstance(modelId: number): void {
+ this.availableModelTree.tree.treeModel.getNodeBy((node: ITreeNode) => node.data.id === modelId)
+ .setActiveAndVisible().expand();
+ }
+
+ public highlightInstancesBySelectingNode(id: number): void {
+ if(this.isShowTree()) {
+ let _this = this;
+ let matchInstances = _this.searchTree(id);
+ if (!matchInstances.length)
+ _this.clearSelectionInTree(_this.drawingModelTree.tree);
+ matchInstances.forEach(function (instance, index) {
+ let multi : boolean = !!index;
+ _this.drawingModelTree.tree.treeModel.getNodeById(instance.id)
+ .setActiveAndVisible(multi).expand();
+ });
+
+ }
+ }
+
+ clearSelectionInTree(tree: TreeComponent): void {
+ let activateNode = tree.treeModel.getActiveNode();
+ activateNode ? activateNode.toggleActivated().blur() : null;
+ }
+
+ searchTree(modelId: number) {
+ let _this = this;
+ let results = [];
+ let nodes = _this.drawingModelTree.nodes;
+ nodes.forEach(function (node) {
+ _this.searchTreeNode(node, modelId, results);
+ });
+ return results;
+ }
+
+ searchTreeNode(node, modelId: number, results): void {
+ if(node.modelId === modelId){
+ results.push(node);
+ }
+ if (node.children != null){
+ for(let i = 0; i < node.children.length; i++){
+ this.searchTreeNode(node.children[i], modelId, results);
+ }
+ }
+ }
+
+
+}
+
+export class ServicePlanningEmptyComponent extends ServicePlanningComponent {
+ isShowTree() : boolean {
+ return false;
+ }
+}
+
+
diff --git a/vid-webpack-master/src/app/factories/models/requestDetails.model.ts b/vid-webpack-master/src/app/factories/models/requestDetails.model.ts
new file mode 100644
index 000000000..4ccc4781b
--- /dev/null
+++ b/vid-webpack-master/src/app/factories/models/requestDetails.model.ts
@@ -0,0 +1,126 @@
+export class RequestInfo {
+ instanceName: string;
+ source: string;
+ suppressRollback: boolean;
+ requestorId: string;
+ productFamilyId: string;
+}
+
+export class ModelInfo {
+ modelType: string;
+ modelInvariantId: string;
+ modelVersionId: string;
+ modelName: string;
+ modelVersion: string;
+ modelCustomizationId: string;
+ modelCustomizationName: string;
+}
+
+export class RequestParameters {
+ userParams: any[];
+ testApi: string;
+}
+
+export class CloudConfiguration {
+ lcpCloudRegionId: string;
+ tenantId: string;
+}
+
+export class LineOfBusiness {
+ lineOfBusinessName: string;
+}
+
+export class Platform {
+ platformName: string;
+}
+
+export class VfcModel {
+ uuid: string;
+ invariantUuid: string;
+ name: string;
+ version: string;
+ vfcInstanceGroupProperties : any;
+}
+
+export class RelatedInstance {
+ instanceId: string;
+ modelInfo: ModelInfo;
+}
+
+export class RelatedInstanceList {
+ relatedInstance: RelatedInstance;
+}
+
+export class RequestDetails {
+ requestInfo: RequestInfo;
+ modelInfo: ModelInfo;
+ requestParameters: RequestParameters;
+ cloudConfiguration: CloudConfiguration;
+ lineOfBusiness: LineOfBusiness;
+ platform: Platform;
+ relatedInstanceList: RelatedInstanceList[];
+}
+
+export class RootObject {
+ requestDetails: RequestDetails;
+}
+// {
+// "requestDetails": {
+// "modelInfo": {
+// “modelType”: “vnf”,
+// “modelInvariantId”: “ff5256d1-5a33-55df-13ab-12abad84e7ff”,
+// “modelVersionId”: “fe042c22-ba82-43c6-b2f6-8f1fc4164091”,
+// “modelName”: “vSAMP12”,
+// "modelVersion": "1.0",
+// “modelCustomizationName”: “vSAMP12 1”,
+// “modelCustomizationId”: “a7f1d08e-b02d-11e6-80f5-76304dec7eb7”
+// },
+// “cloudConfiguration”: {
+// “lcpCloudRegionId”: “mdt1”,
+// “tenantId”: “88a6ca3ee0394ade9403f075db23167e”
+// },
+// "requestInfo": {
+// “instanceName”: “MSOTEST103a”,
+// “productFamilyId”: “a9a77d5a-123e-4ca2-9eb9-0b015d2ee0fb”,
+// “source”: “VID”,
+// “suppressRollback”: false,
+// “requestorId”: “az2016”
+// },
+// "platform": {
+// "platformName": "{some platformName}"
+// },
+// "lineOfBusiness": {
+// "lineOfBusinessName": "{some string}"
+// },
+// "relatedInstanceList": [
+// {
+// “relatedInstance”: {
+// “instanceId”: “{serviceInstanceId}”,
+// “modelInfo”: {
+// “modelType”: “service”,
+// “modelInvariantId”: “ff3514e3-5a33-55df-13ab-12abad84e7ff”,
+// “modelVersionId”: “fe6985cd-ea33-3346-ac12-ab121484a3fe”,
+// “modelName”: “{parent service model name}”,
+// "modelVersion": "1.0"
+// }
+// }
+// },
+// {
+// “relatedInstance”: {
+// “instanceId”: “{instanceGroupId}”,
+// “modelInfo”: {
+// “modelType”: “networkCollection”,
+// “modelInvariantId”: “9ea660dc-155f-44d3-b45c-cc7648b4f31c”,
+// “modelVersionId”: “bb07aad1-ce2d-40c1-85cb-5392f76bb1ef”,
+// “modelName”: “{network collection model name}”,
+// "modelVersion": "1.0"
+// }
+// }
+// }
+
+// ],
+// “requestParameters”: {
+// “userParams”: []
+// }
+// }
+// }
diff --git a/vid-webpack-master/src/app/factories/mso.factory.spec.ts b/vid-webpack-master/src/app/factories/mso.factory.spec.ts
new file mode 100644
index 000000000..16efd2970
--- /dev/null
+++ b/vid-webpack-master/src/app/factories/mso.factory.spec.ts
@@ -0,0 +1,319 @@
+import {createRequest} from './mso.factory';
+
+sessionStorage.setItem("msoRequestParametersTestApiValue","GR_API");
+describe('Vlantagging', () => {
+ it('should create a correct request', (done: DoneFn) => {
+ let userInputs_withEcompGeneratedNaming = {
+ "productFamily": "e433710f-9217-458d-a79d-1c7aff376d89",
+ "lcpRegion": "AAIAIC25",
+ "tenantId": "092eb9e8e4b7412e8787dd091bc58e86",
+ "aicZone": "YYY1",
+ "platformName": "plat1",
+ "lineOfBusiness": "ecomp"
+ };
+ let userInputs_withoutEcompGeneratedNaming = {
+ "instanceName": "New Name",
+ "productFamily": "e433710f-9217-458d-a79d-1c7aff376d89",
+ "lcpRegion": "AAIAIC25",
+ "tenantId": "092eb9e8e4b7412e8787dd091bc58e86",
+ "aicZone": "YYY1",
+ "platformName": "plat1",
+ "lineOfBusiness": "ecomp"
+ };
+ let service = {
+ "service": {
+ "uuid": "6bce7302-70bd-4057-b48e-8d5b99e686ca",
+ "invariantUuid": "9aa04749-c02c-432d-a90c-18caa361c833",
+ "name": "vDBE_srv",
+ "version": "1.0",
+ "toscaModelURL": null,
+ "category": "Network L4+",
+ "serviceType": "",
+ "serviceRole": "",
+ "description": "vDBE_srv",
+ "serviceEcompNaming": "true",
+ "instantiationType": "A-La-Carte",
+ "inputs": {}
+ },
+ "vnfs": {
+ "vDBE 0": {
+ "uuid": "61535073-2e50-4141-9000-f66fea69b433",
+ "invariantUuid": "fcdf49ce-6f0b-4ca2-b676-a484e650e734",
+ "description": "vDBE",
+ "name": "vDBE",
+ "version": "0.2",
+ "customizationUuid": "1",
+ "inputs": {},
+ "commands": {},
+ "properties": {
+ "nf_naming": "{ecomp_generated_naming=true}",
+ "multi_stage_design": "false",
+ "oam_vfc_instance_group_function": "oambbb",
+ "availability_zone_max_count": "1",
+ "oam_network_collection_function": "oamaaa",
+ "ecomp_generated_naming": "true",
+ "untr_vfc_instance_group_function": "untrbbb",
+ "untr_network_collection_function": "untraaa"
+ },
+ "type": "VF",
+ "modelCustomizationName": "vDBE 0",
+ "vfModules": {
+ "vdbe0..Vdbe..main..module-0": {
+ "uuid": "25a4d009-2f5a-44b4-b02a-62c584c15912",
+ "invariantUuid": "614afb1a-3e7e-44e9-90ab-424d0070c781",
+ "customizationUuid": "3443b341-7b0b-498c-a84a-a7ee736cba7e",
+ "description": null,
+ "name": "Vdbe..main..module-0",
+ "version": "1",
+ "modelCustomizationName": "Vdbe..main..module-0",
+ "properties": {
+ "minCountInstances": 1,
+ "maxCountInstances": 1,
+ "initialCount": 1,
+ "vfModuleLabel": "main"
+ },
+ "inputs": {},
+ "volumeGroupAllowed": false
+ }
+ },
+ "volumeGroups": {},
+ "vfcInstanceGroups": {
+ "untr_group": {
+ "uuid": "5fca04e2-a889-4579-8338-f60f1bf285fa",
+ "invariantUuid": "fb1e384b-117a-46ae-9ad1-bf2f1ee1e49f",
+ "name": "untr_group",
+ "version": "1",
+ "vfcInstanceGroupProperties": {
+ "vfcParentPortRole": "untr",
+ "networkCollectionFunction": "untraaa",
+ "vfcInstanceGroupFunction": null,
+ "subinterfaceRole": "untr"
+ }
+ },
+ "oam_group": {
+ "uuid": "a0efd5fc-f7be-4502-936a-a6c6392b958f",
+ "invariantUuid": "9384abf9-1231-4da4-bd8d-89e4d2f8a749",
+ "name": "oam_group",
+ "version": "1",
+ "vfcInstanceGroupProperties": {
+ "vfcParentPortRole": "untr",
+ "networkCollectionFunction": "untraaa",
+ "vfcInstanceGroupFunction": null,
+ "subinterfaceRole": "untr"
+ }
+ }
+ }
+ }
+ },
+ "networks": {},
+ "collectionResource": {},
+ "configurations": {},
+ "serviceProxies": {},
+ "vfModules": {
+ "vdbe0..Vdbe..main..module-0": {
+ "uuid": "25a4d009-2f5a-44b4-b02a-62c584c15912",
+ "invariantUuid": "614afb1a-3e7e-44e9-90ab-424d0070c781",
+ "customizationUuid": "3443b341-7b0b-498c-a84a-a7ee736cba7e",
+ "description": null,
+ "name": "Vdbe..main..module-0",
+ "version": "1",
+ "modelCustomizationName": "Vdbe..main..module-0",
+ "properties": {
+ "minCountInstances": 1,
+ "maxCountInstances": 1,
+ "initialCount": 1,
+ "vfModuleLabel": "main"
+ },
+ "inputs": {},
+ "volumeGroupAllowed": false
+ }
+ },
+ "volumeGroups": {},
+ "pnfs": {}
+ };
+ let serviceInstanceId: string = "6bce7302-70bd-4057-b48e-8d5b99e686ca";
+ let networkInstanceGroups = {
+ "untr_group": {
+ "instance-group": {
+ "instance-group-role": "JZmha7QSS4tJ",
+ "model-invariant-id": "model-id3",
+ "model-version-id": "a0efd5fc-f7be-4502-936a-a6c6392b958f",
+ "id": "AAI-12002-test3-vm230w",
+ "description": "a9DEa0kpY",
+ "instance-group-type": "type",
+ "resource-version": "1520888659539",
+ "instance-group-name": "wKmBXiO1xm8bK",
+ "instance-group-function": "testfunction2",
+ "relationship-list": {
+ "relationship": [
+ {
+ "relationDataList": [
+ {
+ "relationship-key": "cloud-region.cloud-owner",
+ "relationship-value": "AAI-12002-vm230w"
+ },
+ {
+ "relationship-key": "cloud-region.cloud-region-id",
+ "relationship-value": "AAI-region-vm230w"
+ }
+ ],
+ "relatedToPropertyList": [
+ {
+ "property-key": "cloud-region.owner-defined-type",
+ "property-value": null
+ }
+ ],
+ "related-to": "cloud-region",
+ "related-link": "/aai/v13/cloud-infrastructure/cloud-regions/cloud-region/AAI-12002-vm230w/AAI-region-vm230w",
+ "relationship-label": "org.onap.relationships.inventory.Uses",
+ "relationship-data": [
+ {
+ "relationship-key": "cloud-region.cloud-owner",
+ "relationship-value": "AAI-12002-vm230w"
+ },
+ {
+ "relationship-key": "cloud-region.cloud-region-id",
+ "relationship-value": "AAI-region-vm230w"
+ }
+ ],
+ "related-to-property": [
+ {
+ "property-key": "cloud-region.owner-defined-type",
+ "property-value": null
+ }
+ ]
+ }
+ ]
+ }
+ }
+ },
+ "oam_group": {
+ "instance-group": {
+ "instance-group-role": "JZmha7QSS4tJ",
+ "model-invariant-id": "model-id3",
+ "model-version-id": "a0efd5fc-f7be-4502-936a-a6c6392b958f",
+ "id": "AAI-12002-test3-vm230w",
+ "description": "a9DEa0kpY",
+ "instance-group-type": "type",
+ "resource-version": "1520888659539",
+ "instance-group-name": "wKmBXiO1xm8bK",
+ "instance-group-function": "testfunction2",
+ "relationship-list": {
+ "relationship": [
+ {
+ "relationDataList": [
+ {
+ "relationship-key": "cloud-region.cloud-owner",
+ "relationship-value": "AAI-12002-vm230w"
+ },
+ {
+ "relationship-key": "cloud-region.cloud-region-id",
+ "relationship-value": "AAI-region-vm230w"
+ }
+ ],
+ "relatedToPropertyList": [
+ {
+ "property-key": "cloud-region.owner-defined-type",
+ "property-value": null
+ }
+ ],
+ "related-to": "cloud-region",
+ "related-link": "/aai/v13/cloud-infrastructure/cloud-regions/cloud-region/AAI-12002-vm230w/AAI-region-vm230w",
+ "relationship-label": "org.onap.relationships.inventory.Uses",
+ "relationship-data": [
+ {
+ "relationship-key": "cloud-region.cloud-owner",
+ "relationship-value": "AAI-12002-vm230w"
+ },
+ {
+ "relationship-key": "cloud-region.cloud-region-id",
+ "relationship-value": "AAI-region-vm230w"
+ }
+ ],
+ "related-to-property": [
+ {
+ "property-key": "cloud-region.owner-defined-type",
+ "property-value": null
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+ };
+ let expectedResult = {
+ "requestInfo": {
+ "productFamilyId": "e433710f-9217-458d-a79d-1c7aff376d89",
+ "source": "VID",
+ "requestorId": "az2016",
+ "suppressRollback": false
+ },
+ "lineOfBusiness": Object({ lineOfBusinessName: "ecomp" }),
+ "cloudConfiguration": {
+ "lcpCloudRegionId": "AAIAIC25",
+ "tenantId": "092eb9e8e4b7412e8787dd091bc58e86"
+ },
+ "platform": Object({ platformName: "plat1" }),
+ "modelInfo": {
+ modelCustomizationId :'1',
+ "modelVersionId": "61535073-2e50-4141-9000-f66fea69b433",
+ "modelCustomizationName": "vDBE 0",
+ "modelName": "vDBE",
+ "modelInvariantId": "fcdf49ce-6f0b-4ca2-b676-a484e650e734",
+ "modelType": "vnf",
+ "modelVersion": "0.2"
+ },
+ "requestParameters": {
+ "userParams": [],
+ "testApi": "GR_API"
+ },
+ "relatedInstanceList": [
+ {
+ "relatedInstance": {
+ "instanceId": "6bce7302-70bd-4057-b48e-8d5b99e686ca",
+ "modelInfo": {
+ "modelVersionId": "6bce7302-70bd-4057-b48e-8d5b99e686ca",
+ "modelName": "vDBE_srv",
+ "modelInvariantId": "9aa04749-c02c-432d-a90c-18caa361c833",
+ "modelType": "service",
+ "modelVersion": "1.0"
+ }
+ }
+ },
+ {
+ "relatedInstance": {
+ "instanceId": "AAI-12002-test3-vm230w",
+ "modelInfo": {
+ "modelName": "oam_group",
+ "modelType": "networkCollection",
+ "modelVersion": "1",
+ "modelVersionId": "a0efd5fc-f7be-4502-936a-a6c6392b958f",
+ "modelInvariantId": "9384abf9-1231-4da4-bd8d-89e4d2f8a749"
+ }
+ }
+ },
+ {
+ "relatedInstance": {
+ "instanceId": "AAI-12002-test3-vm230w",
+ "modelInfo": {
+ "modelName": "oam_group",
+ "modelType": "networkCollection",
+ "modelVersion": "1",
+ "modelVersionId": "a0efd5fc-f7be-4502-936a-a6c6392b958f",
+ "modelInvariantId": "9384abf9-1231-4da4-bd8d-89e4d2f8a749"
+ }
+ }
+ }
+ ]
+ };
+
+
+ let actualResult_withEcompGeneratedNaming = <any>createRequest("az2016",userInputs_withEcompGeneratedNaming, service, serviceInstanceId, networkInstanceGroups,'vDBE 0','1');
+ expect(actualResult_withEcompGeneratedNaming).toEqual(expectedResult);
+ expectedResult["requestInfo"]["instanceName"] = "New Name";
+ let actualResult_withoutEcompGeneratedNaming = <any>createRequest("az2016",userInputs_withoutEcompGeneratedNaming, service, serviceInstanceId, networkInstanceGroups,'vDBE 0','1');
+ expect(actualResult_withoutEcompGeneratedNaming).toEqual(expectedResult);
+ done();
+ });
+});
diff --git a/vid-webpack-master/src/app/factories/mso.factory.ts b/vid-webpack-master/src/app/factories/mso.factory.ts
new file mode 100644
index 000000000..c26296edf
--- /dev/null
+++ b/vid-webpack-master/src/app/factories/mso.factory.ts
@@ -0,0 +1,92 @@
+import { RequestInfo, RequestDetails, ModelInfo, CloudConfiguration, LineOfBusiness, Platform, RelatedInstanceList, VfcModel } from "./models/requestDetails.model";
+import * as _ from "lodash";
+
+function extractModelInfoFromNodeTemplate(node: any, type: string) {
+ let modelInfo: ModelInfo = <ModelInfo>{};
+ if (node["customizationUuid"] !== undefined) {
+ modelInfo.modelCustomizationId = node["customizationUuid"];
+ }
+ if (node["modelCustomizationName"] !== undefined) {
+ modelInfo.modelCustomizationName = node["modelCustomizationName"];
+ }
+ modelInfo.modelVersionId = node["uuid"];
+ modelInfo.modelName = node["name"];
+ modelInfo.modelInvariantId = node["invariantUuid"];
+ modelInfo.modelType = type;
+ modelInfo.modelVersion = node["version"];
+ return modelInfo;
+}
+
+function extractRequestInfo(userInputs: any, userId: string): RequestInfo {
+ let requestInfo: RequestInfo = <RequestInfo>{};
+ if (userInputs["instanceName"] !== undefined) requestInfo.instanceName = userInputs["instanceName"];
+ requestInfo.productFamilyId = userInputs["productFamily"];
+ requestInfo.source = "VID";
+ requestInfo.suppressRollback = userInputs["rollback"] === "false";
+ requestInfo.requestorId = userId;
+ return requestInfo;
+}
+
+function extractPlatform(userInputs: any): Platform {
+ let platform: Platform = <Platform>{};
+ platform.platformName = userInputs["platformName"];
+ return platform;
+}
+
+function extractVfcGroupModelAccordingToUuid(vnfModel: any, vfcUuid: string) {
+ return _.find(vnfModel.vfcInstanceGroups, { uuid: vfcUuid });
+}
+
+function extractLineOfBusiness(userInputs: any) {
+ let lob: LineOfBusiness = <LineOfBusiness>{};
+ lob.lineOfBusinessName = userInputs["lineOfBusiness"];
+ return lob;
+}
+
+function extractCloudConfiguration(userInputs: any) {
+ let cloudConfig: CloudConfiguration = <CloudConfiguration>{};
+ cloudConfig.lcpCloudRegionId = userInputs["lcpRegion"];
+ cloudConfig.tenantId = userInputs["tenantId"];
+ return cloudConfig;
+}
+
+function extractModelInfoFromVfcNode(vfcModel: VfcModel): ModelInfo {
+ let modelinfo: ModelInfo = <ModelInfo>{};
+ modelinfo.modelName = vfcModel.name;
+ modelinfo.modelType = "networkCollection";
+ modelinfo.modelVersion = vfcModel.version;
+ modelinfo.modelVersionId = vfcModel.uuid;
+ modelinfo.modelInvariantId = vfcModel.invariantUuid;
+ return modelinfo;
+}
+
+export function createRequest(userId: string, userInputs: any, service: any, serviceInstanceId: string, networkInstanceGroups: any, vnfCustomizationName: string, vnfCustomizationId: string) {
+ let request: RequestDetails = <RequestDetails>{};
+ request.requestInfo = extractRequestInfo(userInputs, userId);
+ request.lineOfBusiness = extractLineOfBusiness(userInputs);
+ request.cloudConfiguration = extractCloudConfiguration(userInputs);
+ request.platform = extractPlatform(userInputs);
+ request.modelInfo = extractModelInfoFromNodeTemplate(service.vnfs[vnfCustomizationName], "vnf");
+ request.requestParameters = { userParams: [], testApi: sessionStorage.getItem("msoRequestParametersTestApiValue")};
+ request.relatedInstanceList = [];
+ let serviceRelatedInstance: RelatedInstanceList = {
+ relatedInstance: {
+ instanceId: serviceInstanceId,
+ modelInfo: extractModelInfoFromNodeTemplate(service.service, "service")
+ }
+ };
+ request.relatedInstanceList.push(serviceRelatedInstance);
+ _.forOwn(networkInstanceGroups, function(group) {
+ let modelUuid = group["instance-group"]["model-version-id"];
+ let vfcModel = extractVfcGroupModelAccordingToUuid(service.vnfs[vnfCustomizationName], modelUuid);
+ let networkInstanceGroup: RelatedInstanceList = {
+ relatedInstance: {
+ instanceId: group["instance-group"].id,
+ modelInfo: extractModelInfoFromVfcNode(vfcModel)
+ }
+ };
+ request.relatedInstanceList.push(networkInstanceGroup);
+ });
+
+ return request;
+}
diff --git a/vid-webpack-master/src/app/global.actions.ts b/vid-webpack-master/src/app/global.actions.ts
new file mode 100644
index 000000000..46575fb34
--- /dev/null
+++ b/vid-webpack-master/src/app/global.actions.ts
@@ -0,0 +1,23 @@
+import {Action, ActionCreator} from "redux";
+export const UPDATE_NAME= '[NAME] Update';
+export const UPDATE_FLAGS= '[FLAGS] Update';
+
+export interface UpdateGlobalAction extends Action {
+ name?: string;
+}
+
+export interface UpdateFlagsAction extends Action {
+ flags?: any;
+}
+
+export const updateName: ActionCreator<UpdateGlobalAction> =
+ (name) => ({
+ type: UPDATE_NAME,
+ name: name
+ });
+
+export const updateFlags: ActionCreator<UpdateFlagsAction> =
+ (flags) => ({
+ type: UPDATE_FLAGS,
+ flags: flags
+ });
diff --git a/vid-webpack-master/src/app/global.reducer.ts b/vid-webpack-master/src/app/global.reducer.ts
new file mode 100644
index 000000000..cffd34603
--- /dev/null
+++ b/vid-webpack-master/src/app/global.reducer.ts
@@ -0,0 +1,29 @@
+/* tslint:disable no-switch-case-fall-through */
+import {Action} from 'redux';
+import {UPDATE_FLAGS, UPDATE_NAME, UpdateFlagsAction, UpdateGlobalAction} from "./global.actions";
+
+
+
+export interface GlobalState {
+ name : string;
+ flags : { [key: string]: boolean };
+}
+
+const initialState: GlobalState = {
+ name : null,
+ flags : null
+};
+
+
+export const GlobalReducer =
+ function (state: GlobalState = initialState, action: Action): GlobalState {
+ switch (action.type) {
+ case UPDATE_NAME:
+ return Object.assign(state, state, (<UpdateGlobalAction>action));
+ case UPDATE_FLAGS:
+ Object.assign(state, (<UpdateFlagsAction>action));
+ return Object.assign({}, state);
+ default:
+ return state;
+ }
+ };
diff --git a/vid-webpack-master/src/app/healthStatus/health-status.component.html b/vid-webpack-master/src/app/healthStatus/health-status.component.html
new file mode 100644
index 000000000..600c873be
--- /dev/null
+++ b/vid-webpack-master/src/app/healthStatus/health-status.component.html
@@ -0,0 +1,36 @@
+<div class="row">
+ <div class="health-status-header">
+ <div>
+ <div class="row" style="margin-left: 0;">
+ <div>
+ <span class="title">Health Status </span>
+ </div>
+ <div class="lastUpdate">
+ <div style="float: left;margin-top: 3px;"><span>Last update: {{lastUpdatedDate | date:'MMM. dd, yyyy | HH:mm'}}</span>
+ </div>
+ <div class="refresh-btn" [ngClass]="{'spin' : !dataIsReady}" (click)="refreshData()">
+ <span class="icon-refresh"></span>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
+<div class="row">
+ <table id="health-status-table" class="table table-bordered">
+ <tbody>
+ <tr class="row spaceUnder" *ngFor="let componentStatus of componentStatuses" [attr.data-tests-id]="'component-'+componentStatus?.component">
+ <td class="col-md-1 col-xs-1 component-name"
+ [attr.data-tests-id]="'component-name-'+componentStatus?.component"
+ [ngClass]="isAvailable(componentStatus) ? 'border-is-ok': 'border-not-ok'">
+ {{componentStatus?.component}}
+ </td>
+ <td class="col-md-11 col-xs-3 component-metadata-cell"
+ [attr.data-tests-id]="'component-metadata-'+componentStatus?.component"
+ [ngClass]="isAvailable(componentStatus) ? 'border-is-ok': 'border-not-ok'">
+ <pre class="component-metadata">{{getMetadata(componentStatus) | json}}</pre>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+</div>
diff --git a/vid-webpack-master/src/app/healthStatus/health-status.component.scss b/vid-webpack-master/src/app/healthStatus/health-status.component.scss
new file mode 100644
index 000000000..0dda6b215
--- /dev/null
+++ b/vid-webpack-master/src/app/healthStatus/health-status.component.scss
@@ -0,0 +1,187 @@
+div.dataTables_wrapper {
+ width: 800px;
+ margin: 0 auto;
+}
+
+.row {
+ margin-left: 15px;
+ margin-right: 15px;
+}
+
+.health-status-header {
+ margin-top: 30px;
+ .title {
+ font-family: OpenSans-Semibold;
+ font-size: 24px;
+ color: #4A4A4A;
+ float: left;
+ }
+
+ .info {
+ width: 18px;
+ height: 18px;
+ border: 0;
+ background-size: auto 100%;
+ cursor: pointer;
+ float: left;
+ margin: 10px;
+ }
+
+ .refresh-btn {
+ float: left;
+ margin-top: 6px;
+ margin-left: 10px;
+ cursor: pointer;
+ }
+
+ .lastUpdate {
+ margin-top: 5px;
+ padding-top: 0px;
+ font-size: 15px;
+ border-left: 1px solid black;
+ float: left;
+ padding-left: 10px;
+ color: gray;
+ height: 26px;
+ margin-left: 10px;
+ }
+
+ .refreshBtn {
+ width: 18px;
+ height: 18px;
+ border: 0;
+ background-size: auto 100%;
+ outline: none;
+ margin-left: 10px;
+ background: transparent;
+ }
+
+ svg-icon use {
+ fill: #0000ff !important;
+ }
+
+ //.sub-title {
+ // font-family: OpenSans-Semibold;
+ // font-size: 14px;
+ // color: #4A4A4A;
+ // margin-left: 0;
+ //}
+}
+
+.loader {
+ border: 5px solid #f3f3f3;
+ border-radius: 50%;
+ border-top: 5px solid #3498db;
+ width: 170px;
+ height: 170px;
+ -webkit-animation: spin 2s linear infinite;
+ animation: spin 2s linear infinite;
+ position: absolute;
+ left: 50%;
+ right: 50%;
+ top: 50%;
+}
+
+/* Safari */
+@-webkit-keyframes spin {
+ 0% { -webkit-transform: rotate(0deg); }
+ 100% { -webkit-transform: rotate(360deg); }
+}
+
+@keyframes spin {
+ 0% { transform: rotate(0deg); }
+ 100% { transform: rotate(360deg); }
+}
+
+
+.spin {
+ -webkit-animation: spin .4s infinite linear;
+ -moz-animation: spin .4s infinite linear;
+ -o-animation: spin .4s infinite linear;
+ animation: spin .4s infinite linear;
+ -webkit-transform-origin: 50% 44%;
+ transform-origin:50% 44%;
+ -ms-transform-origin:50% 44% /* IE 9 */
+}
+
+@-moz-keyframes spin {
+ from {
+ -moz-transform: rotate(0deg);
+ }
+ to {
+ -moz-transform: rotate(360deg);
+ }
+}
+
+@-webkit-keyframes spin {
+ from {
+ -webkit-transform: rotate(0deg);
+ }
+ to {
+ -webkit-transform: rotate(360deg);
+ }
+}
+
+@keyframes spin {
+ from {
+ transform: rotate(0deg);
+ }
+ to {
+ transform: rotate(360deg);
+ }
+}
+
+.icon-refresh:before {
+ font-family: icomoon;
+ content: '\e936';
+}
+
+.row{
+ max-width: 1500px;
+}
+
+.red {
+ color: red;
+}
+
+.border-not-ok {
+ border : 2px solid red;
+}
+
+.border-is-ok {
+ border : 2px solid #2fcc66;
+}
+
+
+.component-name {
+ min-width: 100px;
+ vertical-align: middle;
+ text-align: center;
+ background: #f5f5f5;
+ border-right: unset;
+}
+
+.component-metadata-cell {
+ border-left: unset;
+}
+
+.component-metadata {
+ white-space: pre-wrap;
+ background-color: unset;
+ border: unset;
+ font-family: OpenSans-Semibold;
+ font-size: 12px;
+}
+
+
+.table-bordered {
+ margin-top: 10px;
+ font-family: OpenSans-Semibold;
+ font-size: 12px;
+ overflow-x: auto;
+ display: block;
+ color: #5A5A5A;
+ border: none;
+ border-spacing: 0px 3px;
+ border-collapse: separate;
+}
diff --git a/vid-webpack-master/src/app/healthStatus/health-status.component.ts b/vid-webpack-master/src/app/healthStatus/health-status.component.ts
new file mode 100644
index 000000000..6a9ddfdd7
--- /dev/null
+++ b/vid-webpack-master/src/app/healthStatus/health-status.component.ts
@@ -0,0 +1,42 @@
+import { Component, OnInit } from '@angular/core';
+import {ExternalComponentStatus} from "../shared/models/externalComponentStatus";
+import {HealthStatusService} from "../shared/server/healthStatusService/health-status.service";
+
+@Component({
+ selector: 'app-health-status',
+ templateUrl: './health-status.component.html',
+ styleUrls: ['./health-status.component.scss']
+})
+export class HealthStatusComponent implements OnInit {
+ private componentStatuses: Array<ExternalComponentStatus> = [];
+ private dataIsReady: boolean;
+ private lastUpdatedDate: Date;
+
+ constructor(private _healthStatusService: HealthStatusService) {
+ }
+
+
+ ngOnInit() {
+ this.refreshData();
+ }
+
+ refreshData(): void {
+ this.dataIsReady = false;
+ this._healthStatusService.getProbe()
+ .subscribe((res: Array<ExternalComponentStatus>) => {
+ this.componentStatuses = res;
+ this.dataIsReady = true;
+ this.lastUpdatedDate = new Date();
+ })
+ }
+
+ getMetadata(status : ExternalComponentStatus):string {
+ let metadata = status.metadata;
+ delete metadata.rawData;
+ return metadata;
+ }
+
+ isAvailable(componentStatus: ExternalComponentStatus) {
+ return componentStatus.available;
+ }
+}
diff --git a/vid-webpack-master/src/app/home/home.component.e2e-spec.js b/vid-webpack-master/src/app/home/home.component.e2e-spec.js
new file mode 100644
index 000000000..41203f9d8
--- /dev/null
+++ b/vid-webpack-master/src/app/home/home.component.e2e-spec.js
@@ -0,0 +1,13 @@
+describe('Home', function () {
+
+ beforeEach(function () {
+ browser.get('/');
+ });
+
+ it('should have <my-home>', function () {
+ var home = element(by.css('vid-app my-home'));
+ expect(home.isPresent()).toEqual(true);
+ expect(home.getText()).toEqual("Home Works!");
+ });
+
+});
diff --git a/vid-webpack-master/src/app/home/home.component.html b/vid-webpack-master/src/app/home/home.component.html
new file mode 100644
index 000000000..604d9e1d0
--- /dev/null
+++ b/vid-webpack-master/src/app/home/home.component.html
@@ -0,0 +1,3 @@
+<p>
+ Home Works!
+</p>
diff --git a/vid-webpack-master/src/app/home/home.component.scss b/vid-webpack-master/src/app/home/home.component.scss
new file mode 100644
index 000000000..5db1e17a3
--- /dev/null
+++ b/vid-webpack-master/src/app/home/home.component.scss
@@ -0,0 +1,4 @@
+// component styles are encapsulated and only applied to their components
+* {
+ color: #FFEF00;
+}
diff --git a/vid-webpack-master/src/app/home/home.component.ts b/vid-webpack-master/src/app/home/home.component.ts
new file mode 100644
index 000000000..1adaf0ebf
--- /dev/null
+++ b/vid-webpack-master/src/app/home/home.component.ts
@@ -0,0 +1,30 @@
+import { Component, OnInit } from '@angular/core';
+import { SdcService } from '../services/sdc.service';
+import { DataService } from '../services/data.service';
+
+@Component({
+ selector: 'my-home',
+ templateUrl: './home.component.html',
+ styleUrls: ['./home.component.scss'],
+ providers: [SdcService, DataService]
+})
+export class HomeComponent implements OnInit {
+
+ constructor(private _sdcService: SdcService) {
+ // Do stuff
+ }
+
+ ngOnInit() {
+ console.log('Hello Home');
+ console.log('getServicesModels: ');
+ this._sdcService.getServicesModels().subscribe(
+ // onNext() function
+ value => console.log('value is ', value),
+ // onError() function
+ error => console.log('error is ', error),
+ // onComplete() function
+ () => console.log('completed')
+ );
+ }
+
+}
diff --git a/vid-webpack-master/src/app/instantiationStatus/InstantiationStatus.module.ts b/vid-webpack-master/src/app/instantiationStatus/InstantiationStatus.module.ts
new file mode 100644
index 000000000..01db0f187
--- /dev/null
+++ b/vid-webpack-master/src/app/instantiationStatus/InstantiationStatus.module.ts
@@ -0,0 +1,33 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { InputsModule } from '../modules/inputs.module';
+import { DataTableModule } from 'angular2-datatable';
+import { BootstrapModalModule } from 'ng2-bootstrap-modal';
+import { TooltipModule } from 'ngx-tooltip';
+import { InstantiationStatusComponent } from './instantiationStatus.component';
+import { InstantiationStatusComponentService } from './instantiationStatus.component.service';
+import { SharedModule } from '../shared/shared.module';
+import { AngularSvgIconModule } from 'angular-svg-icon';
+import { ContextMenuModule, ContextMenuService } from 'ngx-contextmenu';
+import {ModalModule, PopoverModule} from 'ngx-bootstrap';
+import {AuditInfoModalComponent} from "./auditInfoModal/auditInfoModal.component";
+
+@NgModule({
+ imports: [
+ CommonModule,
+ FormsModule,
+ ReactiveFormsModule,
+ BootstrapModalModule,
+ DataTableModule,
+ TooltipModule,
+ ModalModule,
+ InputsModule,
+ AngularSvgIconModule,
+ ContextMenuModule,
+ SharedModule.forRoot(),
+ PopoverModule.forRoot()],
+ declarations: [InstantiationStatusComponent, AuditInfoModalComponent],
+ providers: [InstantiationStatusComponentService, ContextMenuService]
+})
+export class InstantiationStatusModule { }
diff --git a/vid-webpack-master/src/app/instantiationStatus/auditInfoModal/auditInfoModal.component.html b/vid-webpack-master/src/app/instantiationStatus/auditInfoModal/auditInfoModal.component.html
new file mode 100644
index 000000000..9386af347
--- /dev/null
+++ b/vid-webpack-master/src/app/instantiationStatus/auditInfoModal/auditInfoModal.component.html
@@ -0,0 +1,84 @@
+<div class="modal fade" bsModal #auditInfoModal="bs-modal" [config]="{backdrop: 'static'}"
+ tabindex="-1" role="dialog" aria-labelledby="dialog-static-name">
+ <div id="audit-info-modal" class="">
+ <div class="modal-content">
+ <div class="modal-header">
+ <button type="button" class="close" (click)="onCancelClick()">&times;</button>
+ <span [attr.data-tests-id]="'audit-info-title'" class="modal-title">{{title}}</span>
+ </div>
+ <div class="modal-body row">
+ <div class="col-md-4 left-panel">
+ <div id="service-model-name" class="row">SERVICE MODEL: {{serviceModelName}}</div>
+ <div class="row service-model">
+ <model-information [modelInformationItems]="modelInfoItems"></model-information>
+ </div>
+ </div>
+ <div class="col-md-8 right-panel">
+ <div class="row"><span class="table-title">VID status</span></div>
+ <div class="row">
+ <table id="service-instantiation-audit-info-vid" class="table table-bordered">
+ <thead class="thead-dark">
+ <tr class="row">
+ <th class="col-md-4" scope="col">Status</th>
+ <th class="col-md-4" scope="col">Status time</th>
+ <th class="col-md-4" scope="col">Final</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr class="row" *ngFor="let data of vidInfoData">
+ <td class="col-md-4" id="vidJobStatus" [attr.data-tests-id]="'vidJobStatus'">
+ <custom-ellipsis [id]="data?.jobStatus" [value]="data?.jobStatus | capitalizeAndFormat"></custom-ellipsis>
+ </td>
+ <td class="col-md-4" id="vidStatusTime">
+ <custom-ellipsis [id]="data?.vidCreated"
+ [value]="data?.createdDate | date:'MMM dd, yyyy HH:mm'"></custom-ellipsis>
+ </td>
+ <td class="col-md-4" id="vidFinalStatus">
+ <custom-ellipsis [id]="data?.final"
+ [value]="data?.final ? 'Yes' : 'No'"></custom-ellipsis>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ <div class="no-result" *ngIf="!isLoading && vidInfoData?.length == 0">There is no data.</div>
+ </div>
+
+ <div class="row"><span class="table-title">MSO status</span></div>
+ <table id="service-instantiation-audit-info-mso" class="table table-bordered">
+ <thead class="thead-dark row">
+ <tr class="row">
+ <th class="col-md-3" scope="col">Request ID</th>
+ <th class="col-md-3" scope="col">Status</th>
+ <th class="col-md-3" scope="col">Status time</th>
+ <th class="col-md-3" scope="col">Additional info</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr class="row" *ngFor="let data of msoInfoData">
+ <td class="col-md-3" id="msoRequestId">
+ <custom-ellipsis [id]="data?.requestId" [value]="data?.requestId"></custom-ellipsis>
+ </td>
+ <td class="col-md-3" id="msoJobStatus">
+ <custom-ellipsis [id]="data?.jobStatus" [value]="data?.jobStatus | capitalizeAndFormat"></custom-ellipsis>
+ </td>
+ <td class="col-md-3" id="msoStatusTime">
+ <custom-ellipsis [id]="data?.vidCreated"
+ [value]="data?.createdDate | date:'MMM dd, yyyy HH:mm'"></custom-ellipsis>
+ </td>
+ <td class="col-md-3" id="msoAdditionalInfo">
+ <custom-ellipsis [id]="data?.additionalInfo" [value]="data?.additionalInfo"></custom-ellipsis>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ <div class="no-result" *ngIf="!isLoading && msoInfoData?.length == 0">There is no data.</div>
+ </div>
+ </div>
+ <div class="modal-footer row">
+ <button id="cancelButton" type="button" class="btn btn-default cancel" (click)="onCancelClick()">
+ Close
+ </button>
+ </div>
+ </div>
+ </div>
+</div>
diff --git a/vid-webpack-master/src/app/instantiationStatus/auditInfoModal/auditInfoModal.component.scss b/vid-webpack-master/src/app/instantiationStatus/auditInfoModal/auditInfoModal.component.scss
new file mode 100644
index 000000000..27b271496
--- /dev/null
+++ b/vid-webpack-master/src/app/instantiationStatus/auditInfoModal/auditInfoModal.component.scss
@@ -0,0 +1,159 @@
+.templatebody.modal-open{
+ position: fixed;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ z-index: 1040;
+ background-color: #000;
+ opacity: 0.5;
+}
+.modal{
+
+ #audit-info-modal {
+
+ .modal-content{
+ border-radius: 0px;
+ border: none;
+ .modal-header{
+ background: #009FDB;
+ font-size: 24px;
+ color: #ffffff;
+ .close{
+ font-size: 32px;
+ font-weight: 200;
+ color: #ffffff;
+ text-shadow: none;
+ filter: none;
+ opacity: 1;
+ &:hover{
+ color: #d2d2d2;
+ }
+ }
+ .modal-title{
+
+ }
+ }
+ .modal-body{
+ padding: 0px;
+ margin: 0px;
+ display: flex;
+ .left-panel{
+ background: #f2f2f2;
+ border-right: 1px solid #D2D2D2;
+ padding-right: 0px;
+ .row:first-child{
+ border-bottom: 1px solid #D2D2D2;
+ height: 50px;
+ font-size: 12px;
+ line-height: 50px;
+ padding-left: 30px;
+ font-weight: 700;
+ margin-right: 0px;
+ }
+ .service-model{
+ padding-left: 30px;
+ padding-top: 15px;
+ }
+ }
+ .right-panel{
+ padding: 30px 30px 15px 30px;
+ .row{
+ margin: 0px;
+ }
+ .table-title{
+ font-size: 12px;
+ text-transform: uppercase;
+ font-weight: bold;
+ }
+ .no-result{
+ margin-bottom: 20px;
+ text-align: center;
+ border: 1px solid #d2d2d2;
+ padding: 20px;
+ margin-top: -23px;
+ }
+
+ .table-bordered{
+ width: 100%;
+ margin-top: 10px;
+ font-family: OpenSans-Semibold;
+ font-size: 12px;
+ overflow-x: auto;
+ display: block;
+ color: #5A5A5A;
+
+ thead {
+ position: sticky;
+ top: 0;
+ z-index: 100;
+ display: block;
+ background: rgb(242, 242, 242);
+ border-bottom: 1px solid #d2d2d2;
+ tr {
+ display: flex;
+ th {
+ flex-grow: 1;
+ border-right: 1px solid #d2d2d2;
+ &:last-child{
+ border-right: none;
+ }
+ }
+ }
+ }
+
+ tbody {
+ border: none !important;
+ max-height: 152px;
+ display: block;
+
+ tr {
+ display: flex;
+ border-bottom: 1px solid #d2d2d2;
+ &:last-child{
+ border-bottom: none;
+ }
+ td {
+ border: none;
+ border-right: 1px solid #d2d2d2;
+ &:last-child{
+ border-right: none;
+ }
+ }
+ }
+ }
+
+ th {
+ background: #f2f2f2;
+ font-family: OpenSans-Semibold;
+ color: #000000;
+ font-weight: bold;
+ border: none;
+ }
+
+ tr.odd {
+ background-color: rgb(242, 242, 242);
+ }
+
+ tr:hover {
+ background: #e1e1e1;
+ }
+ }
+ }
+ }
+ .modal-footer{
+ margin: 0px;
+ .cancel{
+ width: 120px;
+ height: 36px;
+ background: #009fdb;
+ border-radius: 2px;
+ font-family: OpenSans-Regular;
+ font-size: 14px;
+ color: #ffffff;
+ line-height: 16px;
+ }
+ }
+ }
+ }
+}
diff --git a/vid-webpack-master/src/app/instantiationStatus/auditInfoModal/auditInfoModal.component.service.ts b/vid-webpack-master/src/app/instantiationStatus/auditInfoModal/auditInfoModal.component.service.ts
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/vid-webpack-master/src/app/instantiationStatus/auditInfoModal/auditInfoModal.component.service.ts
diff --git a/vid-webpack-master/src/app/instantiationStatus/auditInfoModal/auditInfoModal.component.ts b/vid-webpack-master/src/app/instantiationStatus/auditInfoModal/auditInfoModal.component.ts
new file mode 100644
index 000000000..1cff97f5b
--- /dev/null
+++ b/vid-webpack-master/src/app/instantiationStatus/auditInfoModal/auditInfoModal.component.ts
@@ -0,0 +1,83 @@
+import {Component, ViewChild} from '@angular/core';
+import {Subject} from 'rxjs/Subject';
+import {ModalDirective} from 'ngx-bootstrap'
+import {Constants} from '../../shared/utils/constants';
+import {ModelInformationItem} from '../../shared/components/model-information/model-information.component';
+import {ServiceModel} from '../../shared/models/serviceModel';
+import {ServiceInfoService} from '../../shared/server/serviceInfo/serviceInfo.service';
+import {ServiceInfoModel} from '../../shared/server/serviceInfo/serviceInfo.model';
+import {AuditStatus} from '../../shared/server/serviceInfo/AuditStatus.model';
+import {IframeService} from "../../shared/utils/iframe.service";
+
+@Component({
+ selector: 'audit-info-modal',
+ templateUrl: './auditInfoModal.component.html',
+ styleUrls: ['./auditInfoModal.component.scss']
+})
+export class AuditInfoModalComponent {
+ static openModal: Subject<ServiceInfoModel> = new Subject<ServiceInfoModel>();
+ @ViewChild('auditInfoModal') public auditInfoModal: ModalDirective;
+ title: string = Constants.AuditInfoModal.TITLE;
+ modelInfoItems: Array<ModelInformationItem> = [];
+ serviceModel: ServiceModel;
+ serviceModelName: string;
+ vidInfoData: Array<AuditStatus> = [];
+ msoInfoData: Array<AuditStatus> = [];
+ parentElementClassName = 'content';
+ isLoading = true;
+
+ constructor(private _serviceInfoService: ServiceInfoService, private _iframeService : IframeService) {
+ AuditInfoModalComponent.openModal.subscribe((jobData: ServiceInfoModel) => {
+ this.initializeProperties();
+ if (jobData) {
+ this.openAuditInfoModal(jobData);
+ _iframeService.addClassOpenModal(this.parentElementClassName);
+ this.serviceModelName = jobData.serviceModelName ? jobData.serviceModelName : '';
+ this.auditInfoModal.show();
+ } else {
+ _iframeService.removeClassCloseModal(this.parentElementClassName);
+ this.auditInfoModal.hide();
+ }
+ })
+ }
+
+ initializeProperties() : void {
+ this.modelInfoItems = null;
+ this.vidInfoData = [];
+ this.msoInfoData = [];
+ this.isLoading = true;
+ }
+
+ openAuditInfoModal(jobData: ServiceInfoModel): void {
+ this.modelInfoItems = this.createModelInformationItems(jobData);
+ this.initAuditInfoData(jobData['jobId']);
+ this.auditInfoModal.show();
+ }
+
+ initAuditInfoData(jobId: string) {
+ this._serviceInfoService.getJobAuditStatus(jobId)
+ .subscribe((res: Array<Array<AuditStatus>>) => {
+ this.vidInfoData = res[0];
+ this.msoInfoData = res[1];
+ this.isLoading = false;
+ });
+ }
+
+ createModelInformationItems(serviceModel: ServiceInfoModel): Array<ModelInformationItem> {
+ return [
+ new ModelInformationItem('Subscriber name', 'subscriberName', [serviceModel.subscriberName]),
+ new ModelInformationItem('Service type', 'serviceType', [serviceModel.serviceType]),
+ new ModelInformationItem('Service model version', 'serviceModelVersion', [serviceModel.serviceModelVersion]),
+ new ModelInformationItem('Service instance name', 'serviceInstanceName', [serviceModel.serviceInstanceName], '', true),
+ new ModelInformationItem('Service instance ID', 'serviceInstanceId', [serviceModel.serviceInstanceId]),
+ new ModelInformationItem('Requestor User ID', 'userId', [serviceModel.userId]),
+ ];
+ }
+
+ onCancelClick() {
+ this._iframeService.removeClassCloseModal(this.parentElementClassName);
+ this.initializeProperties();
+ this.auditInfoModal.hide();
+ }
+}
+
diff --git a/vid-webpack-master/src/app/instantiationStatus/instantiationStatus.component.html b/vid-webpack-master/src/app/instantiationStatus/instantiationStatus.component.html
new file mode 100644
index 000000000..e0641d03b
--- /dev/null
+++ b/vid-webpack-master/src/app/instantiationStatus/instantiationStatus.component.html
@@ -0,0 +1,100 @@
+<div class="row">
+ <div class="instantiation-status-header">
+ <div>
+ <div class="row" style="margin-left: 0;">
+ <div>
+ <span class="title">Instantiation Status</span>
+ <span class="icon-info"
+ triggers="mouseenter:mouseleave"
+ popover="This table presents all the instantiation requests you made that are waiting, during or finished instantiating. You may see others requests by removing the Show only my requests checkmark."
+ placement="bottom"></span>
+
+ </div>
+ <div class="lastUpdate">
+ <div style="float: left;margin-top: 3px;"><span>Last update: {{lastUpdatedDate | date:'MMM. dd, yyyy | HH:mm'}}</span></div>
+ <div id="refresh-btn" class="refresh-btn" [ngClass]="{'spin' : !dataIsReady}" (click)="deactivateInterval(); refreshData(); activateInterval();">
+ <span class="icon-refresh"></span>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="instantiation-status-data table-responsive">
+ <table id="instantiation-status" class="table table-bordered">
+ <thead class="thead-dark">
+ <tr>
+ <th scope="col" class="smallTd">User ID</th>
+ <th scope="col" class="normal">Model Name</th>
+ <th scope="col" class="normal">Instance Name</th>
+ <th scope="col" class="smallTd">Model version</th>
+ <th scope="col" class="normal">Subscriber</th>
+ <th scope="col" class="mediumTd">Service Type</th>
+ <th scope="col" class="normal">Region</th>
+ <th scope="col" class="mediumTd">Tenant</th>
+ <th scope="col" class="mediumTd">AIC Zone</th>
+ <th scope="col" class="mediumTd">Project</th>
+ <th scope="col" class="mediumTd">Owning entity</th>
+ <th scope="col" class="smallTd">Pause</th>
+ <th scope="col" class="mediumTd">Date</th>
+ <th scope="col" class="last">Status</th>
+ </tr>
+ </thead>
+ <tbody >
+ <tr *ngFor="let data of serviceInfoData; let i = index" [ngClass]="{'odd' : data.serviceIndex%2 == 1}" [id]="data.jobId" (mouseenter)="currentJobId = data?.jobId">
+ <td class="smallTd" id="userId"><custom-ellipsis [id]="data.userId" [value]="data.userId"></custom-ellipsis></td>
+ <td class="normal" id="serviceModelName"><custom-ellipsis [id]="data.serviceModelName" [value]="data.serviceModelName"></custom-ellipsis></td>
+ <td class="normal" id="serviceInstanceName"><custom-ellipsis [id]="data.serviceInstanceName" [value]="data.serviceInstanceName"></custom-ellipsis></td>
+ <td class="smallTd" id="serviceModelVersion"><custom-ellipsis [id]="data.serviceModelVersion" [value]="data.serviceModelVersion"></custom-ellipsis></td>
+ <td class="normal" id="subscriberName"><custom-ellipsis [id]="data.subscriberName" [value]="data.subscriberName"></custom-ellipsis></td>
+ <td class="mediumTd" id="serviceType"><custom-ellipsis [id]="data.serviceType" [value]="data.serviceType"></custom-ellipsis></td>
+ <td class="normal" id="regionId"><custom-ellipsis [id]="data.regionId" [value]="data.regionId"></custom-ellipsis></td>
+ <td class="mediumTd" id="tenantName"><custom-ellipsis [id]="data.tenantName" [value]="data.tenantName"></custom-ellipsis></td>
+ <td class="mediumTd" id="aicZoneName"><custom-ellipsis [id]="data.aicZoneName" [value]="data.aicZoneName"></custom-ellipsis></td>
+ <td class="mediumTd" id="project"><custom-ellipsis [id]="data.project" [value]="data.project"></custom-ellipsis></td>
+ <td class="mediumTd" id="owningEntityName"><custom-ellipsis [id]="data.owningEntityName" [value]="data.owningEntityName"></custom-ellipsis></td>
+ <td class="smallTd" id="pause"><custom-ellipsis [id]="data.pause" [value]="data.pause"></custom-ellipsis></td>
+ <td class="mediumTd" id="created"><custom-ellipsis [id]="data.created" [value]="data.created | date:'MMM. dd, yyyy HH:mm'"></custom-ellipsis></td>
+ <td class="last" id="jobStatus" [ngClass]="data.jobStatus">
+ <custom-popover [value]="data.serviceStatus.tooltip" style="float: left;">
+ <svg-icon id="jobStatusIcon-{{i}}" (click)="auditInfo(data)" svg-directive [fill]="data.serviceStatus.color" [widthViewBox]="27" [heightViewBox]="27"
+ src="./assets/img/{{data.serviceStatus.iconClassName}}.svg"></svg-icon>
+ </custom-popover>
+ <div class="menu-div" (click)="onContextMenu($event, data); currentJobId = data.jobId">
+ <span class="icon-menu"></span>
+ <context-menu>
+ <ng-template contextMenuItem (execute)="open($event?.item)" [enabled]="isOpenVisible">
+ <div [attr.data-tests-id]="'context-menu-open'">
+ <span class="context-menu-icon"><i class="fa fa-external-link" aria-hidden="true"></i></span>
+ Open
+ </div>
+ </ng-template>
+ <ng-template contextMenuItem (execute)="auditInfo($event?.item)">
+ <div [attr.data-tests-id]="'context-menu-audit-info'">
+ <span class="context-menu-icon audit-icon"><i class="fa fa-info-circle" aria-hidden="true"></i></span>
+ Audit info
+ </div>
+ </ng-template>
+ <ng-template contextMenuItem let-item (execute)="deleteItem($event?.item)" [enabled]="isDeleteEnabled">
+ <div [attr.data-tests-id]="'context-menu-delete'">
+ <span class="context-menu-icon"><i class="fa fa-trash-o" aria-hidden="true"></i></span>
+ Delete
+ </div>
+ </ng-template>
+ <ng-template contextMenuItem let-item (execute)="hideItem($event?.item)" [enabled]="isHideEnabled">
+ <div [attr.data-tests-id]="'context-menu-hide'">
+ <span class="context-menu-icon"><i class="fa fa-eye-slash" aria-hidden="true"></i></span>
+ Hide request
+ </div>
+ </ng-template>
+ </context-menu>
+ </div>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ <audit-info-modal></audit-info-modal>
+</div>
+
+
+
diff --git a/vid-webpack-master/src/app/instantiationStatus/instantiationStatus.component.scss b/vid-webpack-master/src/app/instantiationStatus/instantiationStatus.component.scss
new file mode 100644
index 000000000..65c2400a3
--- /dev/null
+++ b/vid-webpack-master/src/app/instantiationStatus/instantiationStatus.component.scss
@@ -0,0 +1,277 @@
+
+.last {
+ position: sticky;
+ background: #f8f8f8;
+ right: 0;
+ padding-left: 15px;
+ padding-right: 15px;
+ width: 100px !important;
+ max-width: 100px !important;
+ min-width: 85px;
+}
+
+div.dataTables_wrapper {
+ width: 800px;
+ margin: 0 auto;
+}
+
+.row {
+ margin-left: 15px;
+ margin-right: 15px;
+}
+
+.instantiation-status-header {
+ margin-top: 30px;
+ .title {
+ font-family: OpenSans-Semibold;
+ font-size: 24px;
+ color: #4A4A4A;
+ float: left;
+ }
+
+ .info {
+ width: 18px;
+ height: 18px;
+ border: 0;
+ background-size: auto 100%;
+ cursor: pointer;
+ float: left;
+ margin: 10px;
+ }
+
+ .refresh-btn {
+ float: left;
+ margin-top: 6px;
+ margin-left: 10px;
+ cursor: pointer;
+ }
+
+ .lastUpdate {
+ margin-top: 5px;
+ padding-top: 0px;
+ font-size: 15px;
+ border-left: 1px solid black;
+ float: left;
+ padding-left: 10px;
+ color: gray;
+ height: 26px;
+ }
+
+ .refreshBtn {
+ width: 18px;
+ height: 18px;
+ border: 0;
+ background-size: auto 100%;
+ outline: none;
+ margin-left: 10px;
+ background: transparent;
+ }
+
+ svg-icon use {
+ fill: #0000ff !important;
+ }
+
+ .sub-title {
+ font-family: OpenSans-Semibold;
+ font-size: 14px;
+ color: #4A4A4A;
+ margin-left: 0;
+ }
+}
+
+.instantiation-status-data {
+ table {
+ width: 100%;
+ margin-top: 30px;
+ font-family: OpenSans-Semibold;
+ font-size: 12px;
+ overflow-x: auto;
+ display: block;
+ color: #5A5A5A;
+
+ }
+
+ thead {
+ position: sticky;
+ top: 0;
+ z-index: 100;
+ display: block;
+ }
+
+ thead th.normal, tbody td.normal {
+ min-width: 200px !important;
+ max-width: 200px;
+ }
+
+ thead th.smallTd ,tbody td.smallTd {
+ max-width: 100px !important;
+ min-width: 100px !important;
+ }
+
+ thead th.mediumTd ,tbody td.mediumTd {
+ max-width: 150px !important;
+ min-width: 150px !important;
+ }
+
+ tbody {
+ border: none !important;
+ max-height: 500px;
+ display: block;
+ }
+
+ th {
+ background: #f2f2f2;
+ font-family: OpenSans-Semibold;
+ color: #5A5A5A;
+ font-weight: bold;
+ }
+ .menu-div {
+ float: right;
+ border-left: 1px solid gray;
+ height: 23px;
+ }
+
+ tr.odd {
+ background-color: rgb(242, 242, 242);
+ }
+
+ tr:hover {
+ background: #e1e1e1;
+ }
+
+ thead {
+ background: rgb(242, 242, 242);
+ }
+
+ td#jobStatus {
+ cursor: pointer;
+ box-shadow: -2px 1px 5px -2px #aaa;
+ }
+}
+
+
+.loader {
+ border: 5px solid #f3f3f3;
+ border-radius: 50%;
+ border-top: 5px solid #3498db;
+ width: 170px;
+ height: 170px;
+ -webkit-animation: spin 2s linear infinite;
+ animation: spin 2s linear infinite;
+ position: absolute;
+ left: 50%;
+ right: 50%;
+ top: 50%;
+}
+
+/* Safari */
+@-webkit-keyframes spin {
+ 0% { -webkit-transform: rotate(0deg); }
+ 100% { -webkit-transform: rotate(360deg); }
+}
+
+@keyframes spin {
+ 0% { transform: rotate(0deg); }
+ 100% { transform: rotate(360deg); }
+}
+
+
+.spin {
+ -webkit-animation: spin .4s infinite linear;
+ -moz-animation: spin .4s infinite linear;
+ -o-animation: spin .4s infinite linear;
+ animation: spin .4s infinite linear;
+ -webkit-transform-origin: 50% 44%;
+ transform-origin:50% 44%;
+ -ms-transform-origin:50% 44% /* IE 9 */
+}
+
+@-moz-keyframes spin {
+ from {
+ -moz-transform: rotate(0deg);
+ }
+ to {
+ -moz-transform: rotate(360deg);
+ }
+}
+
+@-webkit-keyframes spin {
+ from {
+ -webkit-transform: rotate(0deg);
+ }
+ to {
+ -webkit-transform: rotate(360deg);
+ }
+}
+
+@keyframes spin {
+ from {
+ transform: rotate(0deg);
+ }
+ to {
+ transform: rotate(360deg);
+ }
+}
+
+.icon-refresh:before {
+ font-family: icomoon;
+ content: '\e936';
+}
+
+.icon-info {
+ float: left;
+ margin-top: 10px;
+ margin-left: 10px;
+ font-size: 17px;
+ margin-right: 10px
+}
+
+.icon-info:before {
+ font-family: icomoon;
+ content: '\e91f';
+}
+
+.context-menu-icon{
+ width: 25px;
+ float: left;
+}
+
+.icon-x:before {
+ font-family: icomoon;
+ content: '\e93d';
+}
+
+.icon-inprogress:before {
+ font-family: icomoon;
+ content: '\e899';
+}
+
+.icon-success_o:before {
+ font-family: icomoon;
+ content: '\e934';
+}
+
+.icon-menu:before {
+ font-family: icomoon;
+ content: '\e924';
+ font-size: 22px;
+}
+
+.icon-X_o:before {
+ font-family: icomoon;
+ content: '\e93d';
+ color: #D02B2B;
+}
+
+
+.icon-inprogress:before {
+ font-family: icomoon;
+ content: '\e941';
+ color: #009FDB;
+}
+
+.status-icon {
+ font-size: 20px;
+ margin-top: 0px;
+ height: 0;
+}
diff --git a/vid-webpack-master/src/app/instantiationStatus/instantiationStatus.component.service.spec.ts b/vid-webpack-master/src/app/instantiationStatus/instantiationStatus.component.service.spec.ts
new file mode 100644
index 000000000..c9f434e99
--- /dev/null
+++ b/vid-webpack-master/src/app/instantiationStatus/instantiationStatus.component.service.spec.ts
@@ -0,0 +1,278 @@
+import {getTestBed, TestBed} from '@angular/core/testing';
+import {
+ INPROGRESS,
+ InstantiationStatusComponentService,
+ PAUSE,
+ PENDING,
+ ServiceStatus,
+ STOPED,
+ SUCCESS_CIRCLE,
+ X_O
+} from './instantiationStatus.component.service';
+import {ServiceInfoModel} from '../shared/server/serviceInfo/serviceInfo.model';
+import { Observable } from 'rxjs/Rx';
+
+describe('Instantiation Status Service', () => {
+ let injector;
+ let service: InstantiationStatusComponentService;
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({
+ imports: [],
+ providers: [InstantiationStatusComponentService]
+ });
+
+ injector = getTestBed();
+ service = injector.get(InstantiationStatusComponentService);
+ });
+
+ it('generateServiceInfoDataMapping should return mapping of arrays', (done: DoneFn) => {
+ let data : Array<ServiceInfoModel> = generateServiceInfoData();
+ let result = service.generateServiceInfoDataMapping(data);
+
+ expect(result['1']).toBeDefined();
+ expect(result['2']).toBeDefined();
+ expect(result['3']).toBeDefined();
+
+ expect(result['1'].length).toEqual(2);
+ expect(result['2'].length).toEqual(2);
+ expect(result['3'].length).toEqual(1);
+ done();
+ });
+
+ it('generateServiceInfoDataMapping if array is empty should return empty object', (done: DoneFn) => {
+ let result = service.generateServiceInfoDataMapping([]);
+
+ expect(result['1']).not.toBeDefined();
+ expect(result['2']).not.toBeDefined();
+ expect(result['3']).not.toBeDefined();
+ done();
+ });
+
+ it('convertObjectToArray', (done: DoneFn) => {
+
+ spyOn(service, 'convertObjectToArray').and.returnValue(
+ Observable.of([])
+ );
+
+ let data : Array<ServiceInfoModel> = generateServiceInfoData();
+ service.convertObjectToArray(data).subscribe((result) => {
+ expect(result).toBeDefined();
+ done();
+ });
+ });
+
+ it('getStatusTooltip should return status popover', (done: DoneFn) => {
+ let result : ServiceStatus = service.getStatus('pending');
+ expect(result.tooltip).toEqual('Pending: The service will automatically be sent for instantiation as soon as possible.');
+
+ result = service.getStatus('IN_PROGRESS');
+ expect(result.tooltip).toEqual('In-progress: the service is in process of instantiation.');
+
+ result = service.getStatus('PAUSED');
+ expect(result.tooltip).toEqual('Paused: Service has paused and waiting for your action.\n Select actions from the menu to the right.');
+
+ result = service.getStatus('FAILED');
+ expect(result.tooltip).toEqual('Failed: Service instantiation has failed, load the service to see the error returned.');
+
+ result = service.getStatus('COMPLETED');
+ expect(result.tooltip).toEqual('Completed successfully: Service is successfully instantiated.');
+
+ result = service.getStatus('STOPPED');
+ expect(result.tooltip).toEqual('Stopped: Due to previous failure, will not be instantiated.');
+ done();
+ });
+
+ it('getStatusTooltip should return correct icon per job status', (done: DoneFn) => {
+ let result : ServiceStatus = service.getStatus('pending');
+ expect(result.iconClassName).toEqual(PENDING);
+
+ result = service.getStatus('IN_PROGRESS');
+ expect(result.iconClassName).toEqual(INPROGRESS);
+
+ result = service.getStatus('PAUSED');
+ expect(result.iconClassName).toEqual(PAUSE);
+
+ result = service.getStatus('FAILED');
+ expect(result.iconClassName).toEqual(X_O);
+
+ result = service.getStatus('COMPLETED');
+ expect(result.iconClassName).toEqual(SUCCESS_CIRCLE);
+
+ result = service.getStatus('STOPPED');
+ expect(result.iconClassName).toEqual(STOPED);
+ done();
+ });
+
+
+ function generateServiceInfoData(){
+ return JSON.parse(JSON.stringify([
+ {
+ "created": 1519956533000,
+ "modified": 1521727738000,
+ "createdId": null,
+ "modifiedId": null,
+ "rowNum": null,
+ "auditUserId": null,
+ "auditTrail": null,
+ "jobId": "6748648484",
+ "userId": "2222",
+ "jobStatus": "FAILED",
+ "pause": false,
+ "owningEntityId": "1234",
+ "owningEntityName": null,
+ "project": null,
+ "aicZoneId": null,
+ "aicZoneName": null,
+ "tenantId": null,
+ "tenantName": null,
+ "regionId": null,
+ "regionName": null,
+ "serviceType": null,
+ "subscriberName": null,
+ "serviceInstanceId": "1",
+ "serviceInstanceName": null,
+ "serviceModelId": null,
+ "serviceModelName": null,
+ "serviceModelVersion": null,
+ "createdBulkDate": 1519956533000,
+ "statusModifiedDate": 1520042933000,
+ "templateId": "1",
+ "hidden": false
+ },
+ {
+ "created": 1519956533000,
+ "modified": 1521727738000,
+ "createdId": null,
+ "modifiedId": null,
+ "rowNum": null,
+ "auditUserId": null,
+ "auditTrail": null,
+ "jobId": "6748648484",
+ "userId": "2222",
+ "jobStatus": "FAILED",
+ "pause": false,
+ "owningEntityId": "1234",
+ "owningEntityName": null,
+ "project": null,
+ "aicZoneId": null,
+ "aicZoneName": null,
+ "tenantId": null,
+ "tenantName": null,
+ "regionId": null,
+ "regionName": null,
+ "serviceType": null,
+ "subscriberName": null,
+ "serviceInstanceId": "1",
+ "serviceInstanceName": null,
+ "serviceModelId": null,
+ "serviceModelName": null,
+ "serviceModelVersion": null,
+ "createdBulkDate": 1519956533000,
+ "statusModifiedDate": 1520042933000,
+ "templateId": "1",
+ "hidden": false
+ },
+ {
+ "created": 1519956533000,
+ "modified": 1521727738000,
+ "createdId": null,
+ "modifiedId": null,
+ "rowNum": null,
+ "auditUserId": null,
+ "auditTrail": null,
+ "jobId": "6748648484",
+ "userId": "2222",
+ "jobStatus": "FAILED",
+ "pause": false,
+ "owningEntityId": "1234",
+ "owningEntityName": null,
+ "project": null,
+ "aicZoneId": null,
+ "aicZoneName": null,
+ "tenantId": null,
+ "tenantName": null,
+ "regionId": null,
+ "regionName": null,
+ "serviceType": null,
+ "subscriberName": null,
+ "serviceInstanceId": "2",
+ "serviceInstanceName": null,
+ "serviceModelId": null,
+ "serviceModelName": null,
+ "serviceModelVersion": null,
+ "createdBulkDate": 1519956533000,
+ "statusModifiedDate": 1520042933000,
+ "templateId": "2",
+ "hidden": false
+ },
+ {
+ "created": 1519956533000,
+ "modified": 1521727738000,
+ "createdId": null,
+ "modifiedId": null,
+ "rowNum": null,
+ "auditUserId": null,
+ "auditTrail": null,
+ "jobId": "6748648484",
+ "userId": "2222",
+ "jobStatus": "FAILED",
+ "pause": false,
+ "owningEntityId": "1234",
+ "owningEntityName": null,
+ "project": null,
+ "aicZoneId": null,
+ "aicZoneName": null,
+ "tenantId": null,
+ "tenantName": null,
+ "regionId": null,
+ "regionName": null,
+ "serviceType": null,
+ "subscriberName": null,
+ "serviceInstanceId": "2",
+ "serviceInstanceName": null,
+ "serviceModelId": null,
+ "serviceModelName": null,
+ "serviceModelVersion": null,
+ "createdBulkDate": 1519956533000,
+ "statusModifiedDate": 1520042933000,
+ "templateId": "2",
+ "hidden": false
+ },
+ {
+ "created": 1519956533000,
+ "modified": 1521727738000,
+ "createdId": null,
+ "modifiedId": null,
+ "rowNum": null,
+ "auditUserId": null,
+ "auditTrail": null,
+ "jobId": "6748648484",
+ "userId": "2222",
+ "jobStatus": "FAILED",
+ "pause": false,
+ "owningEntityId": "1234",
+ "owningEntityName": null,
+ "project": null,
+ "aicZoneId": null,
+ "aicZoneName": null,
+ "tenantId": null,
+ "tenantName": null,
+ "regionId": null,
+ "regionName": null,
+ "serviceType": null,
+ "subscriberName": null,
+ "serviceInstanceId": "3",
+ "serviceInstanceName": null,
+ "serviceModelId": null,
+ "serviceModelName": null,
+ "serviceModelVersion": null,
+ "createdBulkDate": 1519956533000,
+ "statusModifiedDate": 1520042933000,
+ "templateId": "3",
+ "hidden": false
+ }
+ ]));
+ }
+
+});
diff --git a/vid-webpack-master/src/app/instantiationStatus/instantiationStatus.component.service.ts b/vid-webpack-master/src/app/instantiationStatus/instantiationStatus.component.service.ts
new file mode 100644
index 000000000..293397cc9
--- /dev/null
+++ b/vid-webpack-master/src/app/instantiationStatus/instantiationStatus.component.service.ts
@@ -0,0 +1,75 @@
+import {Injectable} from '@angular/core';
+import {ServiceInfoModel, ServiceInfoUiModel} from '../shared/server/serviceInfo/serviceInfo.model';
+import {isNullOrUndefined} from "util";
+import { Observable } from 'rxjs/Observable';
+import 'rxjs/observable/of';
+
+export let PENDING : string = "pending";
+export let INPROGRESS : string = "inprogress";
+export let PAUSE : string = "pause";
+export let X_O : string = "X_o";
+export let SUCCESS_CIRCLE : string = "success+Circle";
+export let STOPED : string = "stoped";
+
+
+@Injectable()
+export class InstantiationStatusComponentService {
+ generateServiceInfoDataMapping(arr: Array<ServiceInfoModel>) : { [serviceInstanceId: string]: Array<ServiceInfoModel>}{
+ let serviceInfoData: { [serviceInstanceId: string]: Array<ServiceInfoModel>; } = {};
+ for(let item of arr){
+ if(isNullOrUndefined(serviceInfoData[item.templateId])){
+ serviceInfoData[item.templateId] = [item];
+ }else {
+ serviceInfoData[item.templateId].push(item);
+ }
+ }
+ return serviceInfoData;
+ }
+
+ convertObjectToArray(arr: Array<ServiceInfoModel>) : Observable<Array<ServiceInfoUiModel>>{
+ const obj = this.generateServiceInfoDataMapping(arr);
+ let index:number = 0;
+ let result = [];
+ for(let item in obj) {
+ obj[item].map(item => {
+ item['serviceStatus'] = this.getStatus(item.jobStatus);
+ item['serviceIndex'] = index;
+ });
+ index++;
+ result = result.concat(obj[item]);
+ }
+
+ console.log(result);
+ return Observable.of(result);
+ }
+
+ getStatus(status : string) : ServiceStatus {
+ switch(status.toUpperCase()) {
+ case 'PENDING' :
+ return new ServiceStatus(PENDING, '#009FDB', 'Pending: The service will automatically be sent for instantiation as soon as possible.');
+ case 'IN_PROGRESS' :
+ return new ServiceStatus(INPROGRESS, '#009FDB', 'In-progress: the service is in process of instantiation.');
+ case 'PAUSED' :
+ return new ServiceStatus(PAUSE, '#009FDB', 'Paused: Service has paused and waiting for your action.\n Select actions from the menu to the right.');
+ case 'FAILED' :
+ return new ServiceStatus(X_O, '#D02B2B', 'Failed: Service instantiation has failed, load the service to see the error returned.');
+ case 'COMPLETED' :
+ return new ServiceStatus(SUCCESS_CIRCLE, '#53AD15', 'Completed successfully: Service is successfully instantiated.');
+ case 'STOPPED' :
+ return new ServiceStatus(STOPED, '#D02B2B', 'Stopped: Due to previous failure, will not be instantiated.');
+ }
+ }
+}
+
+
+export class ServiceStatus {
+ iconClassName : string;
+ color : string;
+ tooltip : string;
+
+ constructor(_iconClassName : string, _color : string, _tooltip : string){
+ this.iconClassName = _iconClassName;
+ this.color = _color;
+ this.tooltip = _tooltip;
+ }
+}
diff --git a/vid-webpack-master/src/app/instantiationStatus/instantiationStatus.component.spec.ts b/vid-webpack-master/src/app/instantiationStatus/instantiationStatus.component.spec.ts
new file mode 100644
index 000000000..00b6a9945
--- /dev/null
+++ b/vid-webpack-master/src/app/instantiationStatus/instantiationStatus.component.spec.ts
@@ -0,0 +1,88 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import {InstantiationStatusComponent} from './instantiationStatus.component';
+import {ServiceInfoService} from '../shared/server/serviceInfo/serviceInfo.service';
+import {InstantiationStatusComponentService} from './instantiationStatus.component.service';
+import { ContextMenuModule, ContextMenuService } from 'ngx-contextmenu';
+import {CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';
+import { HttpClientTestingModule } from '@angular/common/http/testing';
+import { ScrollToModule } from '@nicky-lenaers/ngx-scroll-to';
+import { ConfigurationService } from '../services/configuration.service';
+import { LogService } from '../shared/utils/log/log.service';
+
+describe('Instantiation Status Component', () => {
+ let component: InstantiationStatusComponent;
+ let fixture: ComponentFixture<InstantiationStatusComponent>;
+ let enableDeleteItems = [
+ { jobStatus:"PENDING" },
+ { jobStatus:"STOPPED" }];
+ let disableDeleteItems = [
+ { jobStatus:"COMPLETED" },
+ { jobStatus:"FAILED" },
+ {jobStatus:"IN_PROGRESS"},
+ {jobStatus:"UnknownOne"}];
+
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ imports: [HttpClientTestingModule, ContextMenuModule, ScrollToModule.forRoot()],
+ providers: [ServiceInfoService, InstantiationStatusComponentService, ContextMenuService, ConfigurationService, LogService],
+ declarations: [InstantiationStatusComponent],
+ schemas: [ CUSTOM_ELEMENTS_SCHEMA ]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(InstantiationStatusComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('component should initialize basic parameters', (done: DoneFn) => {
+ component.TIMER_TIME_IN_SECONDS = 2;
+ expect(component.TIMER_TIME_IN_SECONDS).toEqual(2);
+ expect(component.dataIsReady).toBeFalsy();
+ expect(component.lastUpdatedDate).toBeNull();
+ done();
+ });
+
+ it('component constructor should call activateInterval and ngOnInit', (done: DoneFn) => {
+ component.refreshData();
+ expect(component.dataIsReady).toBeFalsy();
+ done();
+ });
+
+ it('stopped and pending status isDeleteEnabled button should be enabled, not allowed delete statuses isDeleteEnabled button should be disabled', (done: DoneFn) => {
+ enableDeleteItems.forEach((item) => {
+ let isDeleteEnabled: boolean = component.isDeleteEnabled(item);
+ expect(isDeleteEnabled).toBeTruthy();
+ });
+
+ disableDeleteItems.forEach((item) => {
+ let isDeleteEnabled: boolean = component.isDeleteEnabled(item);
+ expect(isDeleteEnabled).toBeFalsy();
+ });
+ done();
+ });
+
+ it('[COMPLETED, FAILED, STOPPED] status isHideEnable button should be enabled, [IN_PROGRESS, PAUSE, PENDING] status isHideEnable button should be disabled', (done: DoneFn) => {
+ const enableHideItems = [
+ { jobStatus:"COMPLETED" },
+ { jobStatus:"FAILED" },
+ { jobStatus:"STOPPED" }];
+ enableHideItems.forEach((item) => {
+ let isDeleteEnabled: boolean = component.isHideEnabled(item);
+ expect(isDeleteEnabled).toBeTruthy();
+ });
+
+ const disableHideItems = [
+ { jobStatus:"IN_PROGRESS" },
+ { jobStatus:"PAUSE" },
+ { jobStatus:"PENDING" },
+ { jobStatus:"NOT_MATTER"}];
+ disableHideItems.forEach((item) => {
+ let isDeleteEnabled: boolean = component.isHideEnabled(item);
+ expect(isDeleteEnabled).toBeFalsy();
+ });
+ done();
+ });
+});
diff --git a/vid-webpack-master/src/app/instantiationStatus/instantiationStatus.component.ts b/vid-webpack-master/src/app/instantiationStatus/instantiationStatus.component.ts
new file mode 100644
index 000000000..ed45ce43c
--- /dev/null
+++ b/vid-webpack-master/src/app/instantiationStatus/instantiationStatus.component.ts
@@ -0,0 +1,145 @@
+import {AfterViewChecked, Component, ViewChild} from '@angular/core';
+import {ServiceInfoService} from '../shared/server/serviceInfo/serviceInfo.service';
+import {ServiceInfoModel} from '../shared/server/serviceInfo/serviceInfo.model';
+import {InstantiationStatusComponentService} from './instantiationStatus.component.service';
+import {ContextMenuComponent, ContextMenuService} from 'ngx-contextmenu';
+import {AuditInfoModalComponent} from "./auditInfoModal/auditInfoModal.component";
+import * as _ from 'lodash';
+import {ScrollToConfigOptions, ScrollToService} from '@nicky-lenaers/ngx-scroll-to';
+import {ConfigurationService} from "../services/configuration.service";
+import {LogService} from '../shared/utils/log/log.service';
+
+
+@Component({
+ selector : 'instantiation-status',
+ templateUrl : './instantiationStatus.component.html',
+ styleUrls : ['./instantiationStatus.component.scss']
+})
+export class InstantiationStatusComponent implements AfterViewChecked{
+
+
+ TIMER_TIME_IN_SECONDS : number = 0;
+ timer = null;
+ dataIsReady : boolean = false;
+ scroll : boolean = false;
+ lastUpdatedDate: Date = null;
+ currentJobId: string = null;
+ instantiationStatusComponentService: InstantiationStatusComponentService;
+ configurationService : ConfigurationService;
+ serviceInfoData: Array<ServiceInfoModel> = null;
+ @ViewChild(ContextMenuComponent) public contextMenu: ContextMenuComponent;
+
+ constructor(private _serviceInfoService: ServiceInfoService,
+ private _instantiationStatusComponentService : InstantiationStatusComponentService,
+ private _contextMenuService: ContextMenuService,
+ private _configurationService : ConfigurationService,
+ private _scrollToService: ScrollToService,
+ private _logService : LogService) {
+ this.instantiationStatusComponentService = _instantiationStatusComponentService;
+ this.configurationService = this._configurationService;
+ this.configurationService.getConfiguration("refreshTimeInstantiationDashboard").subscribe(response => {
+ this.TIMER_TIME_IN_SECONDS = _.isNumber(response) ? response : 0;
+ this.activateInterval();
+ this.refreshData();
+ });
+ }
+
+ activateInterval() {
+ if (this.TIMER_TIME_IN_SECONDS > 0) {
+ this.timer = setInterval(() => {
+ this.refreshData();
+ }, this.TIMER_TIME_IN_SECONDS * 1000);
+ }
+ }
+
+ deactivateInterval() {
+ clearInterval(this.timer);
+ }
+
+ refreshData(): void {
+ this.dataIsReady = false;
+ this._serviceInfoService.getServicesJobInfo(true)
+ .subscribe((res: Array<ServiceInfoModel>) => {
+ this._instantiationStatusComponentService.convertObjectToArray(res).subscribe((res) => {
+ this._logService.info('refresh instantiation status table', res);
+ this.dataIsReady = true;
+ this.lastUpdatedDate = new Date();
+ if (!_.isEqual(this.serviceInfoData, res)) {
+ this.serviceInfoData = res;
+ this.scroll = true;
+ }
+ });
+ })
+ }
+
+ ngAfterViewChecked(){
+ if (this.scroll) {
+ this.scrollToElement();
+ this.scroll = false;
+ }
+ }
+
+
+
+ isDeleteEnabled(item):boolean {
+ return _.includes(['PENDING', 'STOPPED'], item.jobStatus);
+ }
+
+ deleteItem(item): void {
+ this._serviceInfoService.deleteJob(item.jobId).subscribe(() => {
+ this.refreshData();
+ });
+ }
+
+ hideItem(item): void {
+ this._serviceInfoService.hideJob(item.jobId).subscribe(() => {
+ this.refreshData();
+ });
+ }
+
+ auditInfo(jobData : ServiceInfoModel): void {
+ AuditInfoModalComponent.openModal.next(jobData);
+
+ }
+
+ isOpenVisible(item):boolean {
+ return _.includes(['COMPLETED', 'PAUSE'], item.jobStatus);
+ }
+
+ open(item): void {
+ let query =
+ `subscriberId=${item['subscriberName']}&` +
+ `serviceType=${item['serviceType']}&` +
+ `serviceInstanceId=${item['serviceInstanceId']}`;
+
+ window.parent.location.assign('../../serviceModels.htm#/instantiate?' + query);
+ }
+
+ public onContextMenu($event: MouseEvent, item: any): void {
+ this._contextMenuService.show.next({
+ contextMenu: this.contextMenu,
+ event: $event,
+ item: item,
+ });
+ $event.preventDefault();
+ $event.stopPropagation();
+ }
+
+ getImagesSrc(imageName : string) : string {
+ return './' + imageName + '.svg';
+ }
+
+ isHideEnabled(item: any):boolean {
+ return _.includes(['COMPLETED', 'FAILED', 'STOPPED'], item.jobStatus);
+ }
+ scrollToElement() {
+ if(this.currentJobId){
+ const config: ScrollToConfigOptions = {
+ target: this.currentJobId,
+ duration: 50,
+ offset: -35 //header height
+ };
+ this._scrollToService.scrollTo(config);
+ }
+ }
+}
diff --git a/vid-webpack-master/src/app/modules/inputs.module.ts b/vid-webpack-master/src/app/modules/inputs.module.ts
new file mode 100644
index 000000000..cb5f914cd
--- /dev/null
+++ b/vid-webpack-master/src/app/modules/inputs.module.ts
@@ -0,0 +1,20 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { DynamicInputsComponent } from '../components/dynamic-inputs/dynamic-inputs.component';
+import { AngularMultiSelectModule } from "angular2-multiselect-dropdown";
+import { DynamicInputLabelPipe } from '../shared/pipes/dynamicInputLabel/dynamic-input-label.pipe';
+
+
+@NgModule({
+ imports: [
+ CommonModule, FormsModule, ReactiveFormsModule, AngularMultiSelectModule
+ ],
+ providers: [],
+ declarations: [ DynamicInputLabelPipe, DynamicInputsComponent ],
+ entryComponents: [],
+ exports: [ DynamicInputLabelPipe, DynamicInputsComponent ]
+
+})
+
+export class InputsModule { }
diff --git a/vid-webpack-master/src/app/service.actions.ts b/vid-webpack-master/src/app/service.actions.ts
new file mode 100644
index 000000000..a62fec673
--- /dev/null
+++ b/vid-webpack-master/src/app/service.actions.ts
@@ -0,0 +1,197 @@
+import { Action, ActionCreator } from "redux";
+import { LcpRegionsAndTenants } from "./shared/models/lcpRegionsAndTenants";
+import { ServiceInstance } from "./shared/models/serviceInstance";
+import { SelectOptionInterface } from "./shared/models/selectOption";
+import { ServiceType } from "./shared/models/serviceType";
+import { VnfInstance } from "./shared/models/vnfInstance";
+
+export const UPDATE_MODEL = "[MODEL] Update";
+export const UPDATE_SERVICE_INSTANCE = "[SERVICE INSTANCE] Update";
+export const UPDATE_VNF_INSTANCE = "[VNF INSTANCE] Update";
+export const UPDATE_VF_MODULE = "[VF MODULE] Update";
+export const CREATE_VF_MODULE = "[VF MODULE] Create";
+
+export const UPDATE_LCP_REGIONS_AND_TENANTS = "[LCP_REGIONS_AND_TENANTS] Update";
+export const UPDATE_SUBSCRIBERS = "[SUBSCRIBERS] Update";
+export const UPDATE_PRODUCT_FAMILIES = "[PRODUCT_FAMILIES] Update";
+export const UPDATE_SERVICE_TYPES = "[SERVICE_TYPE] Update";
+export const UPDATE_AIC_ZONES = "[AIC_ZONES] Update";
+export const DELETE_SERVICE_INSTANCE = "[SERVICE_INSTANCE] Delete";
+export const DELETE_VNF_INSTANCE = "[VNF_INSTANCE] Delete";
+export const DELETE_VNF_MODULE_INSTANCE = "[VNF_MODULE_INSTANCE] Delete";
+export const UPDATE_CATEGORY_PARAMETERS = "[CATEGORY_PARAMETERS] Update";
+export const UPDATE_NETWORK_FUNCTION = "[UPDATE_NETWORK_FUNCTION] Update";
+export const UPDATE_USER_ID = "[UPDATE_USER_ID] Update";
+
+
+export interface UpdateServiceModelAction extends Action {
+ serviceHierarchy?: any;
+}
+
+export interface UpdateNetworkCollectionFunction extends Action {
+ networksAccordingToNetworkCollection: any;
+ network_function: any;
+}
+
+export interface UpdateServiceInstanceAction extends Action {
+ serviceUuid?: string;
+ serviceInstance?: ServiceInstance;
+}
+
+export interface UpdateVFModuleInstanceAction extends Action {
+ vfInstance: any;
+ vfId: string;
+ serviceUuid: string;
+}
+
+export interface CreateVFModuleInstanceAction extends Action {
+ vfInstance: any;
+ vfId: string;
+ serviceUuid: string;
+ index : number
+}
+
+export interface UpdateUserIdAction extends Action {
+ userId: string;
+}
+
+export interface UpdateVnfInstanceAction extends Action {
+ vnfInstance?: VnfInstance;
+ vnfModelName?: string;
+ serviceUuid?: string;
+}
+
+export interface UpdateLcpRegionsAndTenantsAction extends Action {
+ lcpRegionsAndTenants?: LcpRegionsAndTenants;
+}
+
+export interface UpdateSubscribersAction extends Action {
+ subscribers?: SelectOptionInterface[];
+}
+
+export interface UpdateProductFamiliesAction extends Action {
+ productFamilies?: SelectOptionInterface[];
+}
+
+export interface UpdateAicZonesAction extends Action {
+ aicZones?: SelectOptionInterface[];
+}
+
+export interface UpdateServiceTypesAction extends Action {
+ serviceTypes?: ServiceType[];
+ subscriberId: string;
+}
+
+export interface DeleteServiceInstanceAction extends Action {
+ serviceUuid?: string;
+}
+
+export interface DeleteVnfInstanceAction extends Action {
+ modelName?: string;
+ serviceModelId: string;
+}
+
+export interface DeleteVfModuleInstanceAction extends Action {
+ modelName?: string;
+ serviceModelId?: string;
+ vfName?: string;
+}
+
+export interface UpdateCategoryParametersAction extends Action {
+ categoryParameters?: string;
+}
+
+export const updateModel: ActionCreator<UpdateServiceModelAction> = serviceHierarchy => ({
+ type: UPDATE_MODEL,
+ serviceHierarchy: serviceHierarchy
+});
+
+export const updateServiceInstance: ActionCreator<UpdateServiceInstanceAction> = (serviceInstance, serviceUuid) => ({
+ type: UPDATE_SERVICE_INSTANCE,
+ serviceInstance: serviceInstance,
+ serviceUuid: serviceUuid
+});
+
+export const updateVFModuleInstance: ActionCreator<UpdateVFModuleInstanceAction> = (vfInstance, vfId, serviceUuid) => ({
+ type: UPDATE_VF_MODULE,
+ vfInstance: vfInstance,
+ vfId: vfId,
+ serviceUuid: serviceUuid
+})
+
+export const createVFModuleInstance: ActionCreator<CreateVFModuleInstanceAction> = (vfInstance, vfId, serviceUuid, index) => ({
+ type: CREATE_VF_MODULE,
+ vfInstance: vfInstance,
+ vfId: vfId,
+ serviceUuid: serviceUuid,
+ index : index
+})
+
+
+
+export const updateVNFInstance: ActionCreator<UpdateVnfInstanceAction> = (vnfInstance, vnfModelName, serviceUuid) => ({
+ type: UPDATE_VNF_INSTANCE,
+ vnfInstance: vnfInstance,
+ vnfModelName: vnfModelName,
+ serviceUuid: serviceUuid
+});
+
+export const updateLcpRegionsAndTenants: ActionCreator<UpdateLcpRegionsAndTenantsAction> = lcpRegionsAndTenants => ({
+ type: UPDATE_LCP_REGIONS_AND_TENANTS,
+ lcpRegionsAndTenants: lcpRegionsAndTenants
+});
+
+export const updateSubscribers: ActionCreator<UpdateSubscribersAction> = subscribers => ({
+ type: UPDATE_SUBSCRIBERS,
+ subscribers: subscribers
+});
+
+export const updateProductFamilies: ActionCreator<UpdateProductFamiliesAction> = productFamilies => ({
+ type: UPDATE_PRODUCT_FAMILIES,
+ productFamilies: productFamilies
+});
+
+export const updateAicZones: ActionCreator<UpdateAicZonesAction> = aicZones => ({
+ type: UPDATE_AIC_ZONES,
+ aicZones: aicZones
+});
+
+export const updateUserId: ActionCreator<UpdateUserIdAction> = userId => ({
+ type: UPDATE_USER_ID,
+ userId: userId
+});
+
+export const updateCategoryParameters: ActionCreator<UpdateCategoryParametersAction> = categoryParameters => ({
+ type: UPDATE_CATEGORY_PARAMETERS,
+ categoryParameters: categoryParameters
+});
+
+export const updateServiceTypes: ActionCreator<UpdateServiceTypesAction> = (serviceTypes, subscriberId) => ({
+ type: UPDATE_SERVICE_TYPES,
+ serviceTypes: serviceTypes,
+ subscriberId: subscriberId
+});
+
+export const updateNetworkCollectionFunction: ActionCreator<UpdateNetworkCollectionFunction> = (ncf, networksAccordingToNetworkCollection) => ({
+ type: UPDATE_NETWORK_FUNCTION,
+ networksAccordingToNetworkCollection: networksAccordingToNetworkCollection["results"],
+ network_function: ncf
+});
+
+export const deleteServiceInstance: ActionCreator<DeleteServiceInstanceAction> = serviceUuid => ({
+ type: DELETE_SERVICE_INSTANCE,
+ serviceUuid: serviceUuid
+});
+
+export const deleteVnfInstance: ActionCreator<DeleteVnfInstanceAction> = (modelName, serviceModelId) => ({
+ type: DELETE_VNF_INSTANCE,
+ modelName: modelName,
+ serviceModelId: serviceModelId
+});
+
+export const deleteVfModuleInstance: ActionCreator<DeleteVfModuleInstanceAction> = (modelName, serviceModelId, vfName) => ({
+ type: DELETE_VNF_MODULE_INSTANCE,
+ modelName: modelName,
+ serviceModelId: serviceModelId,
+ vfName: vfName
+});
diff --git a/vid-webpack-master/src/app/service.reducer.spec.ts b/vid-webpack-master/src/app/service.reducer.spec.ts
new file mode 100644
index 000000000..f734979ac
--- /dev/null
+++ b/vid-webpack-master/src/app/service.reducer.spec.ts
@@ -0,0 +1,286 @@
+import { LcpRegionsAndTenants } from './shared/models/lcpRegionsAndTenants';
+import { ServiceReducer, ServiceState } from './service.reducer';
+import { CategoryParams } from './shared/models/categoryParams';
+import {
+ DELETE_VNF_INSTANCE, DELETE_VNF_MODULE_INSTANCE, DeleteVfModuleInstanceAction,
+ DeleteVnfInstanceAction,
+ UPDATE_AIC_ZONES,
+ UPDATE_LCP_REGIONS_AND_TENANTS,
+ UPDATE_PRODUCT_FAMILIES,
+ UPDATE_SERVICE_INSTANCE,
+ UPDATE_SUBSCRIBERS,
+ UPDATE_USER_ID,
+ UPDATE_VNF_INSTANCE,
+ UpdateAicZonesAction,
+ UpdateProductFamiliesAction, UpdateServiceInstanceAction,
+ UpdateSubscribersAction, UpdateUserIdAction,
+ UpdateVnfInstanceAction
+} from './service.actions';
+import { VnfInstance } from './shared/models/vnfInstance';
+import { ServiceInstance } from './shared/models/serviceInstance';
+import { LcpRegion } from './shared/models/lcpRegion';
+import { Tenant } from './shared/models/tenant';
+import { SelectOption } from './shared/models/selectOption';
+
+
+const initialState: ServiceState = {
+ serviceHierarchy: {},
+ serviceInstance: {},
+ lcpRegionsAndTenants: new LcpRegionsAndTenants(),
+ subscribers: null,
+ productFamilies: null,
+ serviceTypes: {},
+ aicZones: null,
+ categoryParameters: new CategoryParams()
+};
+
+
+describe('service reducer', () => {
+ const userId: string = 'userId';
+ it('should handle initial state', () => {
+ expect(ServiceReducer(undefined, <any>{})).toEqual(initialState);
+ });
+
+ it('#UPDATE_USER_ID : should update userId ', (done: DoneFn) => {
+ expect(ServiceReducer(<any>{},
+ <UpdateUserIdAction>{
+ type: UPDATE_USER_ID,
+ userId: userId
+ }
+ )['userId']).toEqual(userId);
+ done();
+ });
+
+ it('#UPDATE_SERVICE_INSTANCE : should update service instance with service id ', (done: DoneFn) => {
+ const serviceUuid:string = 'serviceUuid';
+
+ let serviceInstanceObject : ServiceInstance = {
+ instanceName: 'instanceName',
+ isUserProvidedNaming: false,
+ globalSubscriberId: 'globalSubscriberId',
+ productFamilyId: 'productFamilyId',
+ subscriptionServiceType: 'subscriptionServiceType',
+ lcpCloudRegionId: 'lcpCloudRegionId',
+ tenantId: 'tenantId',
+ tenantName: 'tenantName',
+ aicZoneId: 'aicZoneId',
+ aicZoneName: 'aicZoneName',
+ projectName: 'projectName',
+ owningEntityId: 'owningEntityId',
+ owningEntityName: 'owningEntityName',
+ pause: false,
+ bulkSize: 1,
+ vnfs: {},
+ instanceParams : {},
+ rollbackOnFailure: false,
+ subscriberName: 'subscriberName'
+ };
+
+ let serviceState = ServiceReducer(<any>{serviceInstance : {}},
+ <UpdateServiceInstanceAction>{
+ type: UPDATE_SERVICE_INSTANCE,
+ serviceUuid: serviceUuid,
+ serviceInstance : serviceInstanceObject
+ }).serviceInstance['serviceUuid'];
+
+ expect(serviceState.instanceName).toEqual(serviceInstanceObject.instanceName);
+ expect(serviceState.isUserProvidedNaming).toEqual(serviceInstanceObject.isUserProvidedNaming);
+ expect(serviceState.globalSubscriberId).toEqual(serviceInstanceObject.globalSubscriberId);
+ expect(serviceState.productFamilyId).toEqual(serviceInstanceObject.productFamilyId);
+ expect(serviceState.subscriptionServiceType).toEqual(serviceInstanceObject.subscriptionServiceType);
+ expect(serviceState.lcpCloudRegionId).toEqual(serviceInstanceObject.lcpCloudRegionId);
+ expect(serviceState.tenantId).toEqual(serviceInstanceObject.tenantId);
+ expect(serviceState.tenantName).toEqual(serviceInstanceObject.tenantName);
+ expect(serviceState.aicZoneId).toEqual(serviceInstanceObject.aicZoneId);
+ expect(serviceState.aicZoneName).toEqual(serviceInstanceObject.aicZoneName);
+ expect(serviceState.projectName).toEqual(serviceInstanceObject.projectName);
+ expect(serviceState.owningEntityId).toEqual(serviceInstanceObject.owningEntityId);
+ expect(serviceState.owningEntityName).toEqual(serviceInstanceObject.owningEntityName);
+ expect(serviceState.pause).toEqual(serviceInstanceObject.pause);
+ expect(serviceState.bulkSize).toEqual(serviceInstanceObject.bulkSize);
+ expect(serviceState.vnfs).toEqual(serviceInstanceObject.vnfs);
+ expect(serviceState.instanceParams).toEqual(serviceInstanceObject.instanceParams);
+ expect(serviceState.rollbackOnFailure).toEqual(serviceInstanceObject.rollbackOnFailure);
+ expect(serviceState.subscriberName).toEqual(serviceInstanceObject.subscriberName);
+
+ done();
+ });
+
+ it('#UPDATE_VNF_INSTANCE : should update vnf instance with service id and vnfModelName ', (done: DoneFn) => {
+ let vnfInstanceObj : VnfInstance = {
+ instanceName: 'instanceName',
+ isUserProvidedNaming: false,
+ productFamilyId: 'productFamilyId',
+ lcpCloudRegionId: 'lcpCloudRegionId',
+ legacyRegion: 'legacyRegion',
+ tenantId: 'tenantId',
+ platformName: 'platformName',
+ lineOfBusiness: 'lineOfBusiness',
+ rollbackOnFailure: 'false',
+ vfModules: {}
+ };
+
+ let vnfState = ServiceReducer(<any>{serviceInstance : {
+ 'serviceUuid' : {
+ vnfs : {}
+ }
+ }},
+ <UpdateVnfInstanceAction>{
+ type: UPDATE_VNF_INSTANCE,
+ serviceUuid : 'serviceUuid',
+ vnfInstance: vnfInstanceObj,
+ vnfModelName : 'vnfModelName'
+ }).serviceInstance['serviceUuid'].vnfs['vnfModelName'];
+
+ expect(vnfState.instanceName).toEqual(vnfInstanceObj.instanceName);
+ expect(vnfState.isUserProvidedNaming).toEqual(vnfInstanceObj.isUserProvidedNaming);
+ expect(vnfState.productFamilyId).toEqual(vnfInstanceObj.productFamilyId);
+ expect(vnfState.lcpCloudRegionId).toEqual(vnfInstanceObj.lcpCloudRegionId);
+ expect(vnfState.legacyRegion).toEqual(vnfInstanceObj.legacyRegion);
+ expect(vnfState.tenantId).toEqual(vnfInstanceObj.tenantId);
+ expect(vnfState.platformName).toEqual(vnfInstanceObj.platformName);
+ expect(vnfState.lineOfBusiness).toEqual(vnfInstanceObj.lineOfBusiness);
+ expect(vnfState.vfModules).toEqual(vnfInstanceObj.vfModules);
+ expect(vnfState.rollbackOnFailure).toEqual(vnfInstanceObj.rollbackOnFailure);
+
+ done();
+ });
+
+ it('#UPDATE_LCP_REGIONS_AND_TENANTS : should update lcp region and tenants', (done: DoneFn) => {
+ let lcpRegionsAndTenantsObj = [
+ {
+ lcpRegionList : [
+ new LcpRegion({
+ "cloudRegionID" : 'cloudRegionID',
+ "is-permitted" : "is-permitted"
+ })
+ ],
+ lcpRegionsTenantsMap : {
+ "lcpRegion" : [new Tenant({
+ "tenantID" : "tenantID",
+ "tenantName" : "tenantName",
+ "is-permitted" : true
+ })]
+ }
+ }
+ ];
+ let lcpRegionsAndTenantsState = ServiceReducer(<any>{serviceInstance : {}},
+ <any>{
+ type: UPDATE_LCP_REGIONS_AND_TENANTS,
+ lcpRegionsAndTenants : lcpRegionsAndTenantsObj
+ })['lcpRegionsAndTenants'];
+
+ expect(lcpRegionsAndTenantsState).toBeDefined();
+ done();
+ });
+
+ it('#UPDATE_SUBSCRIBERS : should update subscribers', (done: DoneFn) => {
+ let subscribersList = [
+ new SelectOption({
+ id : 'id',
+ name : 'name',
+ isPermitted : false
+ })
+ ];
+ let subscribersState = ServiceReducer(<any>{serviceInstance : {}},
+ <UpdateSubscribersAction>{
+ type: UPDATE_SUBSCRIBERS,
+ subscribers : subscribersList
+ })['subscribers'];
+
+ expect(subscribersState).toBeDefined();
+ expect(subscribersState[0].id).toEqual(subscribersList[0].id);
+ expect(subscribersState[0].isPermitted).toEqual(subscribersList[0].isPermitted);
+ expect(subscribersState[0].name).toEqual(subscribersList[0].name);
+
+ done();
+ });
+
+ it('#UpdateProductFamiliesAction : should update product families', (done: DoneFn) => {
+ let productFamiliesObj = [
+ new SelectOption({
+ id : 'id',
+ name : 'name',
+ isPermitted : false
+ })
+ ];
+ let productFamiliesState = ServiceReducer(<any>{serviceInstance : {}},
+ <UpdateProductFamiliesAction>{
+ type: UPDATE_PRODUCT_FAMILIES,
+ productFamilies : productFamiliesObj
+ })['productFamilies'];
+
+ expect(productFamiliesState).toBeDefined();
+ expect(productFamiliesState[0].id).toEqual(productFamiliesObj[0].id);
+ expect(productFamiliesState[0].isPermitted).toEqual(productFamiliesObj[0].isPermitted);
+ expect(productFamiliesState[0].name).toEqual(productFamiliesObj[0].name);
+
+ done();
+ });
+
+ it('#UPDATE_AIC_ZONES : should update aic zones', (done: DoneFn) => {
+ let aicZonesObj = [
+ new SelectOption({
+ id : 'id',
+ name : 'name',
+ isPermitted : false
+ })
+ ];
+ let aicZonesState = ServiceReducer(<any>{serviceInstance : {}},
+ <UpdateAicZonesAction>{
+ type: UPDATE_AIC_ZONES,
+ aicZones : aicZonesObj
+ })['aicZones'];
+
+ expect(aicZonesState).toBeDefined();
+ expect(aicZonesState[0].id).toEqual(aicZonesObj[0].id);
+ expect(aicZonesState[0].isPermitted).toEqual(aicZonesObj[0].isPermitted);
+ expect(aicZonesState[0].name).toEqual(aicZonesObj[0].name);
+
+ done();
+ });
+
+ it('#DELETE_VNF_INSTANCE : should delete existing vnf', (done: DoneFn) => {
+ let state = ServiceReducer(<any>{serviceInstance : {
+ 'serviceModelId' : {
+ vnfs : {
+ 'modelName' : {}
+ }
+ }
+ }},
+ <DeleteVnfInstanceAction>{
+ type: DELETE_VNF_INSTANCE,
+ modelName : 'modelName',
+ serviceModelId : 'serviceModelId'
+ });
+
+ expect(state).toBeDefined();
+ expect(state.serviceInstance[ 'serviceModelId'].vnfs['modelName']).not.toBeDefined();
+ done();
+ });
+
+ it('#DELETE_VNF_MODULE_INSTANCE : should delete existing vnf module', (done: DoneFn) => {
+ let state = ServiceReducer(<any>{serviceInstance : {
+ 'serviceModelId' : {
+ vnfs : {
+ 'vfName' : {
+ vfModules : {
+ 'modelName' : {}
+ }
+ }
+ }
+ }
+ }},
+ <DeleteVfModuleInstanceAction>{
+ type: DELETE_VNF_MODULE_INSTANCE,
+ modelName : 'modelName',
+ vfName : 'vfName',
+ serviceModelId : 'serviceModelId'
+ });
+
+ expect(state).toBeDefined();
+ expect(state.serviceInstance['serviceModelId'].vnfs['vfName'].vfModules['modelName']).not.toBeDefined();
+ done();
+ });
+
+});
diff --git a/vid-webpack-master/src/app/service.reducer.ts b/vid-webpack-master/src/app/service.reducer.ts
new file mode 100644
index 000000000..a11f31e80
--- /dev/null
+++ b/vid-webpack-master/src/app/service.reducer.ts
@@ -0,0 +1,214 @@
+import { Action } from 'redux';
+import {
+ CREATE_VF_MODULE,
+ CreateVFModuleInstanceAction,
+ DELETE_SERVICE_INSTANCE,
+ DELETE_VNF_INSTANCE,
+ DELETE_VNF_MODULE_INSTANCE,
+ DeleteServiceInstanceAction,
+ DeleteVfModuleInstanceAction,
+ DeleteVnfInstanceAction,
+ UPDATE_AIC_ZONES,
+ UPDATE_CATEGORY_PARAMETERS,
+ UPDATE_LCP_REGIONS_AND_TENANTS,
+ UPDATE_MODEL,
+ UPDATE_NETWORK_FUNCTION,
+ UPDATE_PRODUCT_FAMILIES,
+ UPDATE_SERVICE_INSTANCE,
+ UPDATE_SERVICE_TYPES,
+ UPDATE_SUBSCRIBERS,
+ UPDATE_USER_ID,
+ UPDATE_VF_MODULE,
+ UPDATE_VNF_INSTANCE,
+ UpdateAicZonesAction,
+ UpdateCategoryParametersAction,
+ UpdateLcpRegionsAndTenantsAction,
+ UpdateNetworkCollectionFunction,
+ UpdateProductFamiliesAction,
+ UpdateServiceInstanceAction,
+ UpdateServiceModelAction,
+ UpdateServiceTypesAction,
+ UpdateSubscribersAction,
+ UpdateUserIdAction,
+ UpdateVFModuleInstanceAction,
+ UpdateVnfInstanceAction,
+} from './service.actions';
+import { LcpRegionsAndTenants } from './shared/models/lcpRegionsAndTenants';
+import * as _ from 'lodash';
+import { ServiceInstance } from './shared/models/serviceInstance';
+import { CategoryParams } from './shared/models/categoryParams';
+import { SelectOptionInterface } from './shared/models/selectOption';
+import { ServiceType } from './shared/models/serviceType';
+import { VnfInstance } from './shared/models/vnfInstance';
+import { VfModuleMap } from './shared/models/vfModulesMap';
+
+export interface ServiceState {
+ serviceHierarchy: any;
+ serviceInstance: { [uuid: string]: ServiceInstance; };
+ lcpRegionsAndTenants: LcpRegionsAndTenants;
+ subscribers: SelectOptionInterface[];
+ productFamilies: any;
+ serviceTypes: { [subscriberId: string]: ServiceType[]; };
+ aicZones: SelectOptionInterface[];
+ categoryParameters: CategoryParams;
+}
+
+const initialState: ServiceState = {
+ serviceHierarchy: {},
+ serviceInstance: {},
+ lcpRegionsAndTenants: new LcpRegionsAndTenants(),
+ subscribers: null,
+ productFamilies: null,
+ serviceTypes: {},
+ aicZones: null,
+ categoryParameters: new CategoryParams()
+};
+
+export const ServiceReducer =
+ function (state: ServiceState = initialState, action: Action): ServiceState {
+ switch (action.type) {
+ case UPDATE_MODEL: {
+ let uuid = (<UpdateServiceModelAction>action).serviceHierarchy.service.uuid;
+ state.serviceHierarchy[uuid] = _.cloneDeep((<UpdateServiceModelAction>action).serviceHierarchy);
+ return Object.assign({}, state);
+ }
+ case UPDATE_SERVICE_INSTANCE: {
+ const updateServiceInstanceAction = <UpdateServiceInstanceAction>action;
+ const uuid = updateServiceInstanceAction.serviceUuid;
+ const newState = _.cloneDeep(state);
+
+ const serviceInstance: ServiceInstance = newState.serviceInstance[uuid] || new ServiceInstance();
+
+ newState.serviceInstance[uuid] = Object.assign(serviceInstance, updateServiceInstanceAction.serviceInstance);
+ return newState;
+ }
+ case UPDATE_VNF_INSTANCE: {
+ const updateVnfInstanceAction = <UpdateVnfInstanceAction>action;
+ const serviceUuid = updateVnfInstanceAction.serviceUuid;
+ const vnfModelName = updateVnfInstanceAction.vnfModelName;
+
+ const newState = _.cloneDeep(state);
+ const vnfInstance: VnfInstance = newState.serviceInstance[serviceUuid].vnfs[vnfModelName] || new VnfInstance();
+
+ newState.serviceInstance[serviceUuid].vnfs[vnfModelName] = Object.assign(vnfInstance, updateVnfInstanceAction.vnfInstance);
+ return newState;
+ }
+
+
+ case UPDATE_USER_ID: {
+ const updateUserId : UpdateUserIdAction = <UpdateUserIdAction>action;
+ // var newState2 = {...state,'userId':updateUserId.userId}
+ var newState = _.cloneDeep(state);
+ newState['userId'] = updateUserId.userId;
+ return newState;
+
+ // state = (... {userId:action["userId"]},state]}
+ }
+
+ case UPDATE_VF_MODULE: {
+ const updateVFModuleInstanceAction = <UpdateVFModuleInstanceAction>action;
+ const vfInstance = updateVFModuleInstanceAction.vfInstance;
+ const serviceUuid = updateVFModuleInstanceAction.serviceUuid;
+ const vfModuleId = updateVFModuleInstanceAction.vfId;
+ const newState = _.cloneDeep(state);
+ const vnfs = newState.serviceHierarchy[serviceUuid].vnfs;
+ const vnfId = getVfModuleParentVnfId(vnfs, vfModuleId);
+ let vfModulesMap = newState.serviceInstance[serviceUuid].vnfs[vnfId].vfModules[vfModuleId] || new VfModuleMap();
+ vfModulesMap[vfModuleId] = vfInstance;
+ newState.serviceInstance[serviceUuid].vnfs[vnfId].vfModules[vfModuleId] = vfModulesMap;
+ return newState;
+ }
+
+ case CREATE_VF_MODULE: {
+ const updateVFModuleInstanceAction = <CreateVFModuleInstanceAction>action;
+ const vfInstance = updateVFModuleInstanceAction.vfInstance;
+ const serviceUuid = updateVFModuleInstanceAction.serviceUuid;
+ const vfModuleId = updateVFModuleInstanceAction.vfId;
+ const index = updateVFModuleInstanceAction.index;
+ let newState = Object.assign({}, state);
+ const vnfs = newState.serviceHierarchy[serviceUuid].vnfs;
+ const vnfId = getVfModuleParentVnfId(vnfs, vfModuleId);
+ let vfModulesMap = newState.serviceInstance[serviceUuid].vnfs[vnfId].vfModules[vfModuleId] || new VfModuleMap();
+ let randomId = generateId();
+ vfModulesMap[vfModuleId + randomId] = vfInstance;
+
+ newState.serviceInstance[serviceUuid].vnfs[vnfId].vfModules[vfModuleId] = vfModulesMap;
+ return newState;
+ }
+
+
+ case UPDATE_LCP_REGIONS_AND_TENANTS: {
+ Object.assign(state, (<UpdateLcpRegionsAndTenantsAction>action));
+ return Object.assign({}, state);
+ }
+ case UPDATE_SUBSCRIBERS: {
+ Object.assign(state, (<UpdateSubscribersAction>action));
+ return Object.assign({}, state);
+ }
+ case UPDATE_AIC_ZONES: {
+ Object.assign(state, (<UpdateAicZonesAction>action));
+ return Object.assign({}, state);
+ }
+ case UPDATE_PRODUCT_FAMILIES: {
+ Object.assign(state, (<UpdateProductFamiliesAction>action));
+ return Object.assign({}, state);
+ }
+ case UPDATE_NETWORK_FUNCTION: {
+ let networkFunctionReduxObj = state["networkFunctions"] == undefined ? {} : state["networkFunctions"];
+ networkFunctionReduxObj[(<UpdateNetworkCollectionFunction>action).network_function] = (<UpdateNetworkCollectionFunction>action).networksAccordingToNetworkCollection;
+ Object.assign(state, {"networkFunctions":networkFunctionReduxObj});
+ return Object.assign({}, state);
+ }
+ case UPDATE_SERVICE_TYPES: {
+ let subscriberId = (<UpdateServiceTypesAction>action).subscriberId;
+ let serviceTypes = (<UpdateServiceTypesAction>action).serviceTypes;
+ state.serviceTypes[subscriberId] = serviceTypes;
+ return Object.assign({}, state);
+ }
+ case UPDATE_CATEGORY_PARAMETERS: {
+ Object.assign(state, (<UpdateCategoryParametersAction>action));
+ return Object.assign({}, state);
+ }
+ case DELETE_SERVICE_INSTANCE: {
+ const uuid = (<DeleteServiceInstanceAction>action).serviceUuid;
+ if (state.serviceHierarchy[uuid]) {
+ let newState = _.omit(state, ['serviceInstance[' + uuid + ']']);
+ return Object.assign({}, state, newState);
+ }
+ return Object.assign({}, state);
+ }
+ case DELETE_VNF_INSTANCE: {
+ const actionData =(<DeleteVnfInstanceAction>action);
+ if(state.serviceInstance[actionData.serviceModelId]){
+ delete state.serviceInstance[actionData.serviceModelId].vnfs[actionData.modelName];
+ }
+ return Object.assign({}, state);
+ }
+
+ case DELETE_VNF_MODULE_INSTANCE: {
+ const actionData =(<DeleteVfModuleInstanceAction>action);
+ if(state.serviceInstance[actionData.serviceModelId]){
+ delete state.serviceInstance[actionData.serviceModelId].vnfs[actionData.vfName].vfModules[actionData.modelName];
+ }
+ return Object.assign({}, state);
+ }
+ default:
+ return Object.assign({}, state);
+ }
+ };
+
+const generateId = () => {
+ return Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 5);
+};
+
+
+const getVfModuleParentVnfId = (vnfs: object, vfModuleId: string) => {
+ let vnfId = undefined;
+ _.forOwn(vnfs, (value, key) => {
+ if (vnfs[key].vfModules && vnfs[key].vfModules[vfModuleId]) {
+ vnfId = vnfs[key].modelCustomizationName;
+ return false;
+ }
+ });
+ return vnfId;
+};
diff --git a/vid-webpack-master/src/app/services/aaiService/aai.actions.ts b/vid-webpack-master/src/app/services/aaiService/aai.actions.ts
new file mode 100644
index 000000000..649fb1456
--- /dev/null
+++ b/vid-webpack-master/src/app/services/aaiService/aai.actions.ts
@@ -0,0 +1,75 @@
+import {Action, ActionCreator} from "redux";
+
+export const LOAD_PRODUCT_FAMILIES = '[PRODUCT_FAMILIES] Load';
+
+export const LOAD_LCP_TENANT = '[LCP_TENANT] Load';
+
+export const LOAD_AIC_ZONES = '[AIC_ZONES] Load';
+
+export const LOAD_CATEGORY_PARAMETERS = '[LOAD_CATEGORY_PARAMETERS] Load';
+
+export const LOAD_SERVICE_MDOEL_BY_UUID = '[LOAD_SERVICE_MDOEL_BY_UUID] Load';
+
+export const LOAD_NETWORK_ACCORDING_TO_NF = '[LOAD_NETWORK_ACCORDING_TO_NF] Load'
+
+export const LOAD_USER_ID = '[LOAD_USER_ID] Load'
+
+
+export interface LoadProductFamiliesAction extends Action {}
+
+interface LoadLcpTenant extends Action {}
+
+interface LoadAicZones extends Action {}
+
+interface LoadCategoryParameters extends Action {}
+
+interface LoadServiceModelByUuid extends Action {}
+
+interface LoadNetworkAccordingToNetworkCF extends Action{}
+
+interface LoadUserId extends Action{}
+
+
+export const loadServiceAccordingToUuid : ActionCreator<LoadServiceModelByUuid> =
+ (uuid : string) =>({
+ type : LOAD_SERVICE_MDOEL_BY_UUID,
+ modelId : uuid
+ })
+
+
+export const loadProductFamiliesAction: ActionCreator<LoadProductFamiliesAction> =
+ () => ({
+ type: LOAD_PRODUCT_FAMILIES,
+ });
+
+
+export const loadUserId: ActionCreator<LoadUserId> =
+() => ({
+ type: LOAD_USER_ID,
+});
+
+
+ export const loadLcpTenant: ActionCreator<LoadLcpTenant> =
+ () => ({
+ type: LOAD_LCP_TENANT,
+ });
+
+
+export const loadAicZones: ActionCreator<LoadAicZones> =
+ () => ({
+ type: LOAD_AIC_ZONES,
+ });
+
+export const loadCategoryParameters: ActionCreator<LoadCategoryParameters> =
+ () => ({
+ type: LOAD_CATEGORY_PARAMETERS,
+ });
+
+
+export const loadAaiNetworkAccordingToNetworkCF: ActionCreator<LoadNetworkAccordingToNetworkCF> =
+ (networkFunction,cloudOwner,cloudRegionId) => ({
+ type: LOAD_NETWORK_ACCORDING_TO_NF,
+ networkFunctions: networkFunction,
+ cloudOwner: cloudOwner,
+ cloudRegionId: cloudRegionId
+ });
diff --git a/vid-webpack-master/src/app/services/aaiService/aai.epics.ts b/vid-webpack-master/src/app/services/aaiService/aai.epics.ts
new file mode 100644
index 000000000..5249cea82
--- /dev/null
+++ b/vid-webpack-master/src/app/services/aaiService/aai.epics.ts
@@ -0,0 +1,81 @@
+import {updateServiceInstance} from './../../service.actions';
+import {Injectable} from '@angular/core';
+import {createEpicMiddleware} from 'redux-observable';
+import 'rxjs/add/operator/catch';
+import 'rxjs/add/operator/map';
+import 'rxjs/add/operator/do';
+import 'rxjs/add/operator/startWith';
+import {
+ LOAD_PRODUCT_FAMILIES,
+ LOAD_LCP_TENANT,
+ LOAD_AIC_ZONES,
+ LOAD_CATEGORY_PARAMETERS,
+ LOAD_SERVICE_MDOEL_BY_UUID,
+ LOAD_NETWORK_ACCORDING_TO_NF,
+ LOAD_USER_ID
+} from "./aai.actions";
+import {AaiService} from "./aai.service";
+import {
+ updateAicZones, updateCategoryParameters, updateLcpRegionsAndTenants, updateNetworkCollectionFunction,
+ updateProductFamilies, updateUserId
+} from "../../service.actions";
+import {AppState} from "../../store/reducers";
+
+const notFetchedAlready = (state: AppState): boolean => state.service.productFamilies !== null;
+
+@Injectable()
+export class AAIEpics {
+ constructor(private aaiService: AaiService) {
+ }
+
+ public createEpic() {
+ return [createEpicMiddleware(this.loadProductFamiliesEpic)
+ , createEpicMiddleware(this.loadLcpTenants)
+ , createEpicMiddleware(this.loadAicZones)
+ , createEpicMiddleware(this.loadCategoryParameters)
+ , createEpicMiddleware(this.loadServiceAccordingToUuid)
+ , createEpicMiddleware(this.loadNetworkAccordingToNetworkFunction)
+ , createEpicMiddleware(this.loadUserId)
+ ];
+ }
+
+ private loadLcpTenants = (action$, store) =>
+ action$
+ .ofType(LOAD_LCP_TENANT)
+ .switchMap(() => this
+ .aaiService
+ .getLcpRegionsAndTenants('e433710f-9217-458d-a79d-1c7aff376d89', 'VIRTUAL USP')
+ .map(data => updateLcpRegionsAndTenants(data)));
+
+ private loadProductFamiliesEpic = (action$, store) => action$
+ .ofType(LOAD_PRODUCT_FAMILIES)
+ .switchMap(() => this.aaiService.getProductFamilies().map(data => updateProductFamilies(data)));
+
+ private loadCategoryParameters = (action$, store) => action$
+ .ofType(LOAD_CATEGORY_PARAMETERS)
+ .switchMap(() => this.aaiService.getCategoryParameters(null).map(data => updateCategoryParameters(data)));
+
+
+ private loadNetworkAccordingToNetworkFunction = (action$, store) => action$
+ .ofType(LOAD_NETWORK_ACCORDING_TO_NF)
+ .flatMap((action) => this.aaiService.getCRAccordingToNetworkFunctionId(action.networkFunctions, action.cloudOwner, action.cloudRegionId).map((res) =>
+ updateNetworkCollectionFunction(action.networkFunctions, res)));
+
+ private loadServiceAccordingToUuid = (action$, store) => action$
+ .ofType(LOAD_SERVICE_MDOEL_BY_UUID)
+ .switchMap((action) => this.aaiService.getServiceModelById(action.modelId)
+ .map(data => updateServiceInstance(action.uuid, data)));
+
+ private loadUserId = (action$, store) => action$
+ .ofType(LOAD_USER_ID)
+ .switchMap(() => this.aaiService.getUserId()
+ .map(res => updateUserId(res)));
+
+
+ private loadAicZones = (action$, store) => action$
+ .ofType(LOAD_AIC_ZONES)
+ .switchMap(() => this.aaiService.getAicZones().map(data => updateAicZones(data)));
+ // .catch(response => of(this.actions.loadFailed(status)))
+ // .startWith(this.actions.loadStarted()));
+
+}
diff --git a/vid-webpack-master/src/app/services/aaiService/aai.service.ts b/vid-webpack-master/src/app/services/aaiService/aai.service.ts
new file mode 100644
index 000000000..dd9d9fb29
--- /dev/null
+++ b/vid-webpack-master/src/app/services/aaiService/aai.service.ts
@@ -0,0 +1,189 @@
+import {Injectable} from '@angular/core';
+import {HttpClient, HttpHeaders} from '@angular/common/http';
+import { Constants } from '../../shared/utils/constants';
+import { ServiceType } from "../../shared/models/serviceType";
+import {GetSubDetailsResponse} from "./responseInterfaces/getSubDetailsResponseInterface";
+import {Observable} from "rxjs/Observable";
+import * as _ from 'lodash';
+import {CategoryParams} from "../../shared/models/categoryParams";
+import {GetCategoryParamsResponseInterface} from "./responseInterfaces/getCategoryParamsResponseInterface";
+import {Project} from "../../shared/models/project";
+import {OwningEntity} from "../../shared/models/owningEntity";
+import {GetServicesResponseInterface} from "./responseInterfaces/getServicesResponseInterface";
+import {Subscriber} from "../../shared/models/subscriber";
+import {GetSubscribersResponse} from "./responseInterfaces/getSubscribersResponseInterface";
+import {AicZone} from "../../shared/models/aicZone";
+import {GetAicZonesResponse} from "./responseInterfaces/getAicZonesResponseInterface";
+import {LcpRegionsAndTenants} from "../../shared/models/lcpRegionsAndTenants";
+import {LcpRegion} from "../../shared/models/lcpRegion";
+import {Tenant} from "../../shared/models/tenant";
+import {ProductFamily} from "../../shared/models/productFamily"
+import {
+ updateAicZones, updateCategoryParameters, updateLcpRegionsAndTenants, updateModel, updateProductFamilies,
+ updateServiceTypes, updateSubscribers, updateUserId
+} from '../../service.actions';
+import {SelectOption} from '../../shared/models/selectOption';
+import {NgRedux} from "@angular-redux/store";
+import {AppState} from "../../store/reducers";
+import {ResponseContentType, ResponseType} from "@angular/http";
+import 'rxjs/add/operator/do';
+import 'rxjs/add/observable/of';
+import 'rxjs/add/operator/catch';
+
+@Injectable()
+export class AaiService {
+
+ constructor (private http: HttpClient, private store: NgRedux<AppState>) {}
+
+ public getServiceModelById(serviceModelId: string): Observable<any> {
+ if (_.has(this.store.getState().service.serviceHierarchy,serviceModelId)){
+ return Observable.of(<any> JSON.parse(JSON.stringify(this.store.getState().service.serviceHierarchy[serviceModelId])));
+ }
+ let pathQuery: string = Constants.Path.SERVICES_PATH + serviceModelId;
+ return this.http.get(pathQuery).map(res => res )
+ .do((res) => {
+ this.store.dispatch(updateModel(res));
+ });
+ }
+
+ public getUserId() : Observable<any>{
+ return this.http.get("../../getuserID",{responseType: 'text'}).do((res)=>this.store.dispatch(updateUserId(res)));
+ }
+
+
+ public getCRAccordingToNetworkFunctionId(networkCollectionFunction,cloudOwner,cloudRegionId){
+ return this.http.get('../../aai_get_instance_groups_by_cloudregion/'+cloudOwner+'/'+cloudRegionId+'/' + networkCollectionFunction)
+ .map(res=>res).do((res)=>console.log(res));
+ }
+
+ public getCategoryParameters(familyName): Observable<CategoryParams> {
+ familyName = familyName || Constants.Path.PARAMETER_STANDARDIZATION_FAMILY;
+ let pathQuery: string = Constants.Path.GET_CATEGORY_PARAMETERS +"?familyName=" + familyName+ "&r=" + Math.random();
+
+ return this.http.get<GetCategoryParamsResponseInterface>(pathQuery)
+ .map(this.categoryParametersResponseToProductAndOwningEntity)
+ .do(res => {
+ this.store.dispatch(updateCategoryParameters(res))
+ });
+ }
+
+
+
+ categoryParametersResponseToProductAndOwningEntity(res: GetCategoryParamsResponseInterface): CategoryParams {
+ if (res && res.categoryParameters) {
+ const owningEntityList = res.categoryParameters.owningEntity.map(owningEntity => new OwningEntity(owningEntity));
+ const projectList = res.categoryParameters.project.map(project => new Project(project));
+ const lineOfBusinessList = res.categoryParameters.lineOfBusiness.map(owningEntity => new SelectOption(owningEntity));
+ const platformList = res.categoryParameters.platform.map(platform => new SelectOption(platform));
+
+ return new CategoryParams(owningEntityList, projectList, lineOfBusinessList, platformList);
+ } else {
+ return new CategoryParams();
+ }
+ }
+
+ public getProductFamilies(): Observable<ProductFamily[]> {
+ return this.getServices().map(res => res.service.map(service => new ProductFamily(service)));
+ }
+
+ public getServices(): Observable<GetServicesResponseInterface> {
+ let pathQuery: string = Constants.Path.AAI_GET_SERVICES + Constants.Path.ASSIGN + Math.random();
+
+ return this.http.get<GetServicesResponseInterface>(pathQuery);
+ }
+
+ public getSubscribers(): Observable<Subscriber[]> {
+ if (this.store.getState().service.subscribers){
+ return Observable.of(<any> JSON.parse(JSON.stringify(this.store.getState().service.subscribers)));
+ }
+
+ let pathQuery: string = Constants.Path.AAI_GET_SUBSCRIBERS + Constants.Path.ASSIGN + Math.random();
+
+ return this.http.get<GetSubscribersResponse>(pathQuery).map(res =>
+ res.customer.map( subscriber => new Subscriber(subscriber))).do((res) => {
+ this.store.dispatch(updateSubscribers(res));
+ });
+ }
+
+ public getAicZones(): Observable<AicZone[]> {
+ if (this.store.getState().service.aicZones){
+ return Observable.of(<any> JSON.parse(JSON.stringify(this.store.getState().service.aicZones)));
+ }
+
+ let pathQuery: string = Constants.Path.AAI_GET_AIC_ZONES + Constants.Path.ASSIGN + Math.random();
+
+ return this.http.get<GetAicZonesResponse>(pathQuery).map(res =>
+ res.zone.map(aicZone => new AicZone(aicZone))).do((res) => {
+ this.store.dispatch(updateAicZones(res));
+ });
+ }
+
+ public getLcpRegionsAndTenants(globalCustomerId, serviceType): Observable<LcpRegionsAndTenants> {
+ if (this.store.getState().service.lcpRegionsAndTenants.lcpRegionList.length !== 0){
+ return Observable.of(<any> JSON.parse(JSON.stringify(this.store.getState().service.lcpRegionsAndTenants)));
+ }
+ let pathQuery: string = Constants.Path.AAI_GET_TENANTS
+ + globalCustomerId + Constants.Path.FORWARD_SLASH + serviceType + Constants.Path.ASSIGN + Math.random();
+
+ console.log("AaiService:getSubscriptionServiceTypeList: globalCustomerId: "
+ + globalCustomerId);
+ if (globalCustomerId != null) {
+ return this.http.get(pathQuery)
+ .map(this.tenantResponseToLcpRegionsAndTenants).do((res) => {
+ this.store.dispatch(updateLcpRegionsAndTenants(res));
+ });
+ }
+ }
+
+ tenantResponseToLcpRegionsAndTenants(cloudRegionTenantList): LcpRegionsAndTenants {
+
+ const lcpRegionsTenantsMap = {};
+
+ const lcpRegionList = _.uniqBy(cloudRegionTenantList, 'cloudRegionID').map((cloudRegionTenant) => {
+ return new LcpRegion(cloudRegionTenant)
+ });
+
+ lcpRegionList.forEach(region => {
+ lcpRegionsTenantsMap[region.id] = _.filter(cloudRegionTenantList, {'cloudRegionID' : region.id})
+ .map((cloudRegionTenant) => {
+ return new Tenant(cloudRegionTenant)
+ });
+ const reducer = (accumulator, currentValue) => {
+ accumulator.isPermitted = accumulator.isPermitted || currentValue.isPermitted;
+
+ return accumulator;
+ };
+ region.isPermitted = lcpRegionsTenantsMap[region.id].reduce(reducer).isPermitted;
+ });
+
+ return new LcpRegionsAndTenants(lcpRegionList, lcpRegionsTenantsMap);
+ }
+
+ public getServiceTypes(subscriberId): Observable<ServiceType[]> {
+ console.log("AaiService:getSubscriptionServiceTypeList: globalCustomerId: " + subscriberId);
+ if (_.has(this.store.getState().service.serviceTypes, subscriberId)){
+ return Observable.of(<any> JSON.parse(JSON.stringify(this.store.getState().service.serviceTypes[subscriberId])));
+ }
+
+ return this.getSubscriberDetails(subscriberId)
+ .map(this.subDetailsResponseToServiceTypes)
+ .do((res) => {this.store.dispatch(updateServiceTypes(res, subscriberId));});
+ }
+
+ public getSubscriberDetails(subscriberId): Observable<GetSubDetailsResponse> {
+ let pathQuery: string = Constants.Path.AAI_SUB_DETAILS_PATH + subscriberId + Constants.Path.ASSIGN + Math.random();
+
+ if (subscriberId != null) {
+ return this.http.get<GetSubDetailsResponse>(pathQuery);
+ }
+ }
+
+ subDetailsResponseToServiceTypes(res: GetSubDetailsResponse): ServiceType[] {
+ if (res && res['service-subscriptions']) {
+ const serviceSubscriptions = res['service-subscriptions']['service-subscription'];
+ return serviceSubscriptions.map((subscription, index) => new ServiceType(String(index), subscription))
+ } else {
+ return [];
+ }
+ }
+}
diff --git a/vid-webpack-master/src/app/services/aaiService/responseInterfaces/getAicZonesResponseInterface.ts b/vid-webpack-master/src/app/services/aaiService/responseInterfaces/getAicZonesResponseInterface.ts
new file mode 100644
index 000000000..62581c9e2
--- /dev/null
+++ b/vid-webpack-master/src/app/services/aaiService/responseInterfaces/getAicZonesResponseInterface.ts
@@ -0,0 +1,3 @@
+export interface GetAicZonesResponse {
+ zone: any[];
+}
diff --git a/vid-webpack-master/src/app/services/aaiService/responseInterfaces/getCategoryParamsResponseInterface.ts b/vid-webpack-master/src/app/services/aaiService/responseInterfaces/getCategoryParamsResponseInterface.ts
new file mode 100644
index 000000000..06398904c
--- /dev/null
+++ b/vid-webpack-master/src/app/services/aaiService/responseInterfaces/getCategoryParamsResponseInterface.ts
@@ -0,0 +1,10 @@
+interface CategoryParametersResponse {
+ owningEntity: any[],
+ project: any[]
+ lineOfBusiness: any[]
+ platform: any[]
+}
+
+export interface GetCategoryParamsResponseInterface {
+ categoryParameters: CategoryParametersResponse;
+}
diff --git a/vid-webpack-master/src/app/services/aaiService/responseInterfaces/getServiceModelResponseInterface.ts b/vid-webpack-master/src/app/services/aaiService/responseInterfaces/getServiceModelResponseInterface.ts
new file mode 100644
index 000000000..87671155d
--- /dev/null
+++ b/vid-webpack-master/src/app/services/aaiService/responseInterfaces/getServiceModelResponseInterface.ts
@@ -0,0 +1,5 @@
+import {ServiceModelResponseInterface} from "../../../shared/models/serviceModel";
+
+export interface GetServiceModelResponseInterface {
+ service: ServiceModelResponseInterface
+}
diff --git a/vid-webpack-master/src/app/services/aaiService/responseInterfaces/getServicesResponseInterface.ts b/vid-webpack-master/src/app/services/aaiService/responseInterfaces/getServicesResponseInterface.ts
new file mode 100644
index 000000000..ae04055e4
--- /dev/null
+++ b/vid-webpack-master/src/app/services/aaiService/responseInterfaces/getServicesResponseInterface.ts
@@ -0,0 +1,9 @@
+export interface ServiceResponseInterface {
+ 'service-id': string,
+ 'service-description': string
+ 'is-permitted': boolean
+}
+
+export interface GetServicesResponseInterface {
+ service: ServiceResponseInterface[];
+}
diff --git a/vid-webpack-master/src/app/services/aaiService/responseInterfaces/getSubDetailsResponseInterface.ts b/vid-webpack-master/src/app/services/aaiService/responseInterfaces/getSubDetailsResponseInterface.ts
new file mode 100644
index 000000000..dbfb695d0
--- /dev/null
+++ b/vid-webpack-master/src/app/services/aaiService/responseInterfaces/getSubDetailsResponseInterface.ts
@@ -0,0 +1,12 @@
+export interface Subscription {
+ 'service-type': string;
+ 'is-permitted': boolean;
+}
+
+interface ServiceSubscriptions {
+ 'service-subscription': Subscription[];
+}
+
+export interface GetSubDetailsResponse {
+ 'service-subscriptions': ServiceSubscriptions;
+}
diff --git a/vid-webpack-master/src/app/services/aaiService/responseInterfaces/getSubscribersResponseInterface.ts b/vid-webpack-master/src/app/services/aaiService/responseInterfaces/getSubscribersResponseInterface.ts
new file mode 100644
index 000000000..065f66e21
--- /dev/null
+++ b/vid-webpack-master/src/app/services/aaiService/responseInterfaces/getSubscribersResponseInterface.ts
@@ -0,0 +1,5 @@
+import {Subscriber} from "../../../shared/models/subscriber";
+
+export interface GetSubscribersResponse {
+ customer: Subscriber[];
+}
diff --git a/vid-webpack-master/src/app/services/configuration.service.ts b/vid-webpack-master/src/app/services/configuration.service.ts
new file mode 100644
index 000000000..4edd8ffb5
--- /dev/null
+++ b/vid-webpack-master/src/app/services/configuration.service.ts
@@ -0,0 +1,34 @@
+import {Injectable} from '@angular/core';
+import {HttpClient} from "@angular/common/http";
+import {Constants} from "../shared/utils/constants";
+import {Observable} from 'rxjs/Observable';
+import {updateFlags} from "../global.actions";
+import {NgRedux} from "@angular-redux/store";
+import {AppState} from "../store/reducers";
+
+@Injectable()
+export class ConfigurationService {
+ store : NgRedux<AppState>;
+
+ constructor(private _http: HttpClient, _store : NgRedux<AppState>) {
+ this.store = _store;
+ }
+
+ getConfiguration(key : string): Observable<any> {
+ let pathQuery = Constants.Path.CONFIGURATION_PATH;
+ pathQuery = pathQuery.replace("{name}",key);
+ return this._http.get(pathQuery).map(response => response);
+ }
+
+ getFlags(): Observable<{[key: string] : boolean}> {
+ let flags = this.store.getState().global.flags;
+ if (flags) {
+ return Observable.of(flags);
+ }
+ let pathQuery = Constants.Path.FEATURES_FLAG_PATH;
+ return this._http.get<{[key: string] : boolean}>(pathQuery).map(response => {
+ this.store.dispatch(updateFlags(response));
+ return response;
+ });
+ }
+}
diff --git a/vid-webpack-master/src/app/services/data.service.ts b/vid-webpack-master/src/app/services/data.service.ts
new file mode 100644
index 000000000..4f8bf3623
--- /dev/null
+++ b/vid-webpack-master/src/app/services/data.service.ts
@@ -0,0 +1,528 @@
+import { Injectable } from '@angular/core';
+
+@Injectable()
+export class DataService {
+
+ private static _availableVolumeGroupList;
+ private static _cloudRegionTenantList;
+ private static _globalCustomerId;
+ private static _customizationUUID;
+ private static _rescustomizationUUID;
+ private static _inventoryItem;
+ private static _modelId;
+ private static _modelInstanceName;
+ private static _modelInfo;
+ private static _networkInstanceId;
+ private static _serviceIdList;
+ private static _aicZones;
+ private static _aicZone;
+ private static _serviceInstanceId;
+ private static _serviceInstanceName;
+ private static _serviceName;
+ private static _serviceType;
+ private static _serviceUuid;
+ private static _serviceTypeName;
+ private static _createSubscriberName;
+ private static _uploadSupplementoryDataFile;
+ private static _supplementoryDataFile;
+ private static _subscriberId;
+ private static _loggedInUserId;
+ private static _subscriberName;
+ private static _subscribers;
+ private static _subscriptionServiceTypeList;
+ private static _userParams;
+ private static _userServiceInstanceName;
+ private static _vfModuleInstanceId;
+ private static _vnfInstanceId;
+ private static _vfModuleInstanceName;
+ private static _volumeGroupInstanceId;
+ private static _lcpRegion;
+ private static _tenant;
+ private static _treeHandle;
+ private static _serviceInstanceToCustomer;
+ private static _aLaCarte: boolean;
+ private static _macro: boolean;
+ private static _resources;
+ private static _syspropProvStatusList;
+ private static _updatedvnfProvStatus;
+ private static _arbitraryParameters;
+ private static _hideServiceFields;
+ private static _serviceProxies;
+ private static _sourceServiceProxies;
+ private static _collectorServiceProxies;
+ private static _configurationByPolicy;
+ private static _suppressRollback;
+ private static _portMirroningConfigFields;
+ private static _configurationInstanceId: string;
+ private static _configurationStatus: string;
+ private static _portStatus: string;
+ private static _portId: string;
+ private static _pnf;
+ private static _owningEntityProperties;
+
+ static get availableVolumeGroupList() {
+ return this._availableVolumeGroupList;
+ }
+
+ static set availableVolumeGroupList(value) {
+ this._availableVolumeGroupList = value;
+ }
+
+ static get cloudRegionTenantList() {
+ return this._cloudRegionTenantList;
+ }
+
+ static set cloudRegionTenantList(value) {
+ this._cloudRegionTenantList = value;
+ }
+
+ static get globalCustomerId() {
+ return this._globalCustomerId;
+ }
+
+ static set globalCustomerId(value) {
+ this._globalCustomerId = value;
+ }
+
+ static get customizationUUID() {
+ return this._customizationUUID;
+ }
+
+ static set customizationUUID(value) {
+ this._customizationUUID = value;
+ }
+
+ static get rescustomizationUUID() {
+ return this._rescustomizationUUID;
+ }
+
+ static set rescustomizationUUID(value) {
+ this._rescustomizationUUID = value;
+ }
+
+ static get inventoryItem() {
+ return this._inventoryItem;
+ }
+
+ static set inventoryItem(value) {
+ this._inventoryItem = value;
+ }
+
+ static get modelId() {
+ return this._modelId;
+ }
+
+ static set modelId(value) {
+ this._modelId = value;
+ }
+
+ static get modelInstanceName() {
+ return this._modelInstanceName;
+ }
+
+ static set modelInstanceName(value) {
+ this._modelInstanceName = value;
+ }
+
+ static get modelInfo() {
+ return this._modelInfo;
+ }
+
+ static set modelInfo(value) {
+ this._modelInfo = value;
+ }
+
+ static getModelInfo(componentId) {
+ return this._modelInfo[componentId];
+ }
+
+ static setModelInfo(componentId, modelInfo) {
+ if (!this._modelInfo) {
+ this._modelInfo = {};
+ }
+ this._modelInfo[componentId] = modelInfo;
+ }
+
+ static get networkInstanceId() {
+ return this._networkInstanceId;
+ }
+
+ static set networkInstanceId(value) {
+ this._networkInstanceId = value;
+ }
+
+ static get serviceIdList() {
+ return this._serviceIdList;
+ }
+
+ static set serviceIdList(value) {
+ this._serviceIdList = value;
+ }
+
+ static get aicZones() {
+ return this._aicZones;
+ }
+
+ static set aicZones(value) {
+ this._aicZones = value;
+ }
+
+ static get aicZone() {
+ return this._aicZone;
+ }
+
+ static set aicZone(value) {
+ this._aicZone = value;
+ }
+
+ static get serviceInstanceId() {
+ return this._serviceInstanceId;
+ }
+
+ static set serviceInstanceId(value) {
+ this._serviceInstanceId = value;
+ }
+
+ static get serviceInstanceName() {
+ return this._serviceInstanceName;
+ }
+
+ static set serviceInstanceName(value) {
+ this._serviceInstanceName = value;
+ }
+
+ static get serviceName() {
+ return this._serviceName;
+ }
+
+ static set serviceName(value) {
+ this._serviceName = value;
+ }
+
+ static get serviceType() {
+ return this._serviceType;
+ }
+
+ static set serviceType(value) {
+ this._serviceType = value;
+ }
+
+ static get serviceUuid() {
+ return this._serviceUuid;
+ }
+
+ static set serviceUuid(value) {
+ this._serviceUuid = value;
+ }
+
+ static get serviceTypeName() {
+ return this._serviceTypeName;
+ }
+
+ static set serviceTypeName(value) {
+ this._serviceTypeName = value;
+ }
+
+ static get createSubscriberName() {
+ return this._createSubscriberName;
+ }
+
+ static set createSubscriberName(value) {
+ this._createSubscriberName = value;
+ }
+
+ static get uploadSupplementoryDataFile() {
+ return this._uploadSupplementoryDataFile;
+ }
+
+ static set uploadSupplementoryDataFile(value) {
+ this._uploadSupplementoryDataFile = value;
+ }
+
+ static get supplementoryDataFile() {
+ return this._supplementoryDataFile;
+ }
+
+ static set supplementoryDataFile(value) {
+ this._supplementoryDataFile = value;
+ }
+
+ static get subscriberId() {
+ return this._subscriberId;
+ }
+
+ static set subscriberId(value) {
+ this._subscriberId = value;
+ }
+
+ static get loggedInUserId() {
+ return this._loggedInUserId;
+ }
+
+ static set loggedInUserId(value) {
+ this._loggedInUserId = value;
+ }
+
+ static get subscriberName() {
+ return this._subscriberName;
+ }
+
+ static set subscriberName(value) {
+ this._subscriberName = value;
+ }
+
+ static get subscribers() {
+ return this._subscribers;
+ }
+
+ static set subscribers(value) {
+ this._subscribers = value;
+ }
+
+ static get subscriptionServiceTypeList() {
+ return this._subscriptionServiceTypeList;
+ }
+
+ static set subscriptionServiceTypeList(value) {
+ this._subscriptionServiceTypeList = value;
+ }
+
+ static get userParams() {
+ return this._userParams;
+ }
+
+ static set userParams(value) {
+ this._userParams = value;
+ }
+
+ static get userServiceInstanceName() {
+ return this._userServiceInstanceName;
+ }
+
+ static set userServiceInstanceName(value) {
+ this._userServiceInstanceName = value;
+ }
+
+ static get vfModuleInstanceId() {
+ return this._vfModuleInstanceId;
+ }
+
+ static set vfModuleInstanceId(value) {
+ this._vfModuleInstanceId = value;
+ }
+
+ static get vnfInstanceId() {
+ return this._vnfInstanceId;
+ }
+
+ static set vnfInstanceId(value) {
+ this._vnfInstanceId = value;
+ }
+
+ static get vfModuleInstanceName() {
+ return this._vfModuleInstanceName;
+ }
+
+ static set vfModuleInstanceName(value) {
+ this._vfModuleInstanceName = value;
+ }
+
+ static get volumeGroupInstanceId() {
+ return this._volumeGroupInstanceId;
+ }
+
+ static set volumeGroupInstanceId(value) {
+ this._volumeGroupInstanceId = value;
+ }
+
+ static get lcpRegion() {
+ return this._lcpRegion;
+ }
+
+ static set lcpRegion(value) {
+ this._lcpRegion = value;
+ }
+
+ static get tenant() {
+ return this._tenant;
+ }
+
+ static set tenant(value) {
+ this._tenant = value;
+ }
+
+ static get treeHandle() {
+ return this._treeHandle;
+ }
+
+ static set treeHandle(value) {
+ this._treeHandle = value;
+ }
+
+ static get serviceInstanceToCustomer() {
+ return this._serviceInstanceToCustomer;
+ }
+
+ static set serviceInstanceToCustomer(value) {
+ this._serviceInstanceToCustomer = value;
+ }
+
+ static get aLaCarte() {
+ if (!this._aLaCarte) {
+ return true;
+ }
+ return this._aLaCarte;
+ }
+
+ static set aLaCarte(value: boolean) {
+ this._aLaCarte = value;
+ }
+
+ static get macro() {
+ if (!this._macro) {
+ return false;
+ }
+ return this._macro;
+ }
+
+ static set macro(value: boolean) {
+ this._macro = value;
+ }
+
+ static get resources() {
+ return this._resources;
+ }
+
+ static set resources(value) {
+ this._resources = value;
+ }
+
+ static get syspropProvStatusList() {
+ return this._syspropProvStatusList;
+ }
+
+ static set syspropProvStatusList(value) {
+ this._syspropProvStatusList = value;
+ }
+
+ static get updatedvnfProvStatus() {
+ return this._updatedvnfProvStatus;
+ }
+
+ static set updatedvnfProvStatus(value) {
+ this._updatedvnfProvStatus = value;
+ }
+
+ static get arbitraryParameters() {
+ return this._arbitraryParameters;
+ }
+
+ static set arbitraryParameters(value) {
+ this._arbitraryParameters = value;
+ }
+
+ static get hideServiceFields() {
+ return this._hideServiceFields;
+ }
+
+ static set hideServiceFields(value) {
+ this._hideServiceFields = value;
+ }
+
+ static get serviceProxies() {
+ return this._serviceProxies;
+ }
+
+ static set serviceProxies(value) {
+ this._serviceProxies = value;
+ }
+
+ static get sourceServiceProxies() {
+ return this._sourceServiceProxies;
+ }
+
+ static set sourceServiceProxies(value) {
+ this._sourceServiceProxies = value;
+ }
+
+ static get collectorServiceProxies() {
+ return this._collectorServiceProxies;
+ }
+
+ static set collectorServiceProxies(value) {
+ this._collectorServiceProxies = value;
+ }
+
+ static get configurationByPolicy() {
+ return this._configurationByPolicy;
+ }
+
+ static set configurationByPolicy(value) {
+ this._configurationByPolicy = value;
+ }
+
+ static get suppressRollback() {
+ return this._suppressRollback;
+ }
+
+ static set suppressRollback(value) {
+ this._suppressRollback = value;
+ }
+
+ static get portMirroningConfigFields() {
+ return this._portMirroningConfigFields;
+ }
+
+ static set portMirroningConfigFields(value) {
+ this._portMirroningConfigFields = value;
+ }
+
+ static get configurationInstanceId(): string {
+ return this._configurationInstanceId;
+ }
+
+ static set configurationInstanceId(value: string) {
+ this._configurationInstanceId = value;
+ }
+
+ static get configurationStatus(): string {
+ return this._configurationStatus;
+ }
+
+ static set configurationStatus(value: string) {
+ this._configurationStatus = value;
+ }
+
+ static get portStatus(): string {
+ return this._portStatus;
+ }
+
+ static set portStatus(value: string) {
+ this._portStatus = value;
+ }
+
+ static get portId(): string {
+ return this._portId;
+ }
+
+ static set portId(value: string) {
+ this._portId = value;
+ }
+
+ static get pnf() {
+ return this._pnf;
+ }
+
+ static set pnf(value) {
+ this._pnf = value;
+ }
+
+ static get owningEntityProperties() {
+ return this._owningEntityProperties;
+ }
+
+ static set owningEntityProperties(value) {
+ this._owningEntityProperties = value;
+ }
+
+}
diff --git a/vid-webpack-master/src/app/services/flags.resolve.ts b/vid-webpack-master/src/app/services/flags.resolve.ts
new file mode 100644
index 000000000..70449379f
--- /dev/null
+++ b/vid-webpack-master/src/app/services/flags.resolve.ts
@@ -0,0 +1,14 @@
+import {ActivatedRouteSnapshot, Resolve} from "@angular/router";
+import {Injectable} from "@angular/core";
+import {ConfigurationService} from "./configuration.service";
+import {Observable} from "rxjs/Observable";
+
+@Injectable()
+export class FlagsResolve implements Resolve<Observable< { [key: string]: boolean }>> {
+
+ constructor(private _configurationService: ConfigurationService) {}
+
+ resolve(route: ActivatedRouteSnapshot) {
+ return this._configurationService.getFlags();
+ }
+}
diff --git a/vid-webpack-master/src/app/services/msoService/mso.service.ts b/vid-webpack-master/src/app/services/msoService/mso.service.ts
new file mode 100644
index 000000000..1402b50f7
--- /dev/null
+++ b/vid-webpack-master/src/app/services/msoService/mso.service.ts
@@ -0,0 +1,26 @@
+import {Injectable} from "@angular/core";
+import {HttpClient} from "@angular/common/http";
+import {Observable} from "rxjs/Observable";
+import {Constants} from "../../shared/utils/constants";
+
+@Injectable()
+export class MsoService {
+ httpClient: HttpClient;
+
+ constructor(http: HttpClient) {
+ this.httpClient = http;
+ }
+
+
+ public submitMsoTask(instanceFields): Observable<any> {
+ let path = '../../asyncInstantiation/bulk';
+ return this.httpClient.post(path, instanceFields);
+ }
+ public createVnf(requestDetails, serviceInstanceId): Observable<any> {
+ let pathQuery: string = Constants.Path.MSO_CREATE_VNF_INSTANCE + serviceInstanceId;
+
+ return this.httpClient.post( pathQuery, {
+ requestDetails : requestDetails
+ });
+ }
+}
diff --git a/vid-webpack-master/src/app/services/sdc.service.ts b/vid-webpack-master/src/app/services/sdc.service.ts
new file mode 100644
index 000000000..d4eba260a
--- /dev/null
+++ b/vid-webpack-master/src/app/services/sdc.service.ts
@@ -0,0 +1,28 @@
+import { Injectable } from '@angular/core';
+import { HttpClient } from '@angular/common/http';
+import 'rxjs/add/operator/map';
+import { Constants } from '../shared/utils/constants';
+import { VidConfiguration } from '../configuration/vid.configuration';
+
+@Injectable()
+export class SdcService {
+
+
+ constructor (private http: HttpClient) {
+ }
+
+ public getServicesModels(): any {
+ let pathQuery: string = Constants.Path.SERVICES_DIST_STATUS_PATH + VidConfiguration.ASDC_MODEL_STATUS;
+
+ if ( VidConfiguration.ASDC_MODEL_STATUS === Constants.Status.ALL) {
+ pathQuery = Constants.Path.SERVICES_PATH;
+ }
+
+ return this.http.get(pathQuery);
+ }
+
+ getService(uuid: string) {
+ return this.http.get(Constants.Path.SERVICES_PATH + uuid);
+ }
+
+}
diff --git a/vid-webpack-master/src/app/services/service-planning.service.spec.ts b/vid-webpack-master/src/app/services/service-planning.service.spec.ts
new file mode 100644
index 000000000..5d60e29f7
--- /dev/null
+++ b/vid-webpack-master/src/app/services/service-planning.service.spec.ts
@@ -0,0 +1,467 @@
+import {ServicePlanningService} from "./service-planning.service";
+import {ReflectiveInjector} from "@angular/core";
+import {NgRedux} from "@angular-redux/store";
+import {ServiceNodeTypes} from "../shared/models/ServiceNodeTypes";
+
+export class MockAppStore<T> {
+}
+
+describe('Service planning service', () => {
+ let injector;
+ let service: ServicePlanningService;
+
+ beforeEach(() => {
+
+ let injector = ReflectiveInjector.resolveAndCreate([
+ ServicePlanningService,
+ {provide: NgRedux, useClass: MockAppStore}
+ ]);
+
+ service = injector.get(ServicePlanningService);
+ });
+
+ describe('#updateDynamicInputsVnfDataFromModel', () => {
+ it('get vfModule instance params', (done: DoneFn) => {
+ //get vfModule instance params
+ let dynamicInputs = service.updateDynamicInputsVnfDataFromModel(ServiceNodeTypes.VFmodule, generateVFModule());
+ expect(dynamicInputs).toEqual([{
+ id: '2017488_adiodvpe0_vnf_config_template_version',
+ type: 'string',
+ name: '2017488_adiodvpe0_vnf_config_template_version',
+ value: '17.2',
+ isRequired: true,
+ description: 'VPE Software Version'
+ }, {
+ id: '2017488_adiodvpe0_AIC_CLLI',
+ type: 'string',
+ name: '2017488_adiodvpe0_AIC_CLLI',
+ value: 'ATLMY8GA',
+ isRequired: true,
+ description: 'AIC Site CLLI'
+ }]);
+
+ //get vfModule with no instance params should return empty array
+ dynamicInputs = service.updateDynamicInputsVnfDataFromModel(ServiceNodeTypes.VFmodule, generateVFModule2);
+ expect(dynamicInputs).toEqual([]);
+
+ //get vf instance params should be undefined
+ dynamicInputs = service.updateDynamicInputsVnfDataFromModel(ServiceNodeTypes.VF, generateVNF());
+ expect(dynamicInputs).toEqual([]);
+ done();
+ });
+ });
+
+ describe('#isUserProvidedNaming', () => {
+ it('get vfModule with generate ecompNaming should return userProvided false', (done: DoneFn) => {
+ //get vfModule with generate ecompNaming should return userProvided false
+ let isUserProvidedNaming = service.isUserProvidedNaming(ServiceNodeTypes.VFmodule, generateVFModule(), generateVNF());
+ expect(isUserProvidedNaming).toBeFalsy();
+
+ //get vfModule without generate ecompNaming should return userProvided true
+ isUserProvidedNaming = service.isUserProvidedNaming(ServiceNodeTypes.VFmodule, generateVFModule(), generateVNF_ecompNamingFalse());
+ expect(isUserProvidedNaming).toBeTruthy();
+
+ //get vnf with generate ecompNaming should return userProvided false
+ isUserProvidedNaming = service.isUserProvidedNaming(ServiceNodeTypes.VF, generateVNF(), null);
+ expect(isUserProvidedNaming).toBeFalsy();
+
+ //get vnf without generate ecompNaming should return userProvided true
+ isUserProvidedNaming = service.isUserProvidedNaming(ServiceNodeTypes.VF, generateVNF_ecompNamingFalse(), null);
+ expect(isUserProvidedNaming).toBeTruthy();
+ done();
+ });
+ });
+
+ function generateVFModule() {
+ return {
+ 'uuid': '25284168-24bb-4698-8cb4-3f509146eca5',
+ 'invariantUuid': '7253ff5c-97f0-4b8b-937c-77aeb4d79aa1',
+ 'customizationUuid': 'f7e7c365-60cf-49a9-9ebf-a1aa11b9d401',
+ 'description': null,
+ 'name': '2017488AdiodVpe..ADIOD_vRE_BV..module-1',
+ 'version': '6',
+ 'modelCustomizationName': '2017488AdiodVpe..ADIOD_vRE_BV..module-1',
+ 'properties': {'minCountInstances': 0, 'maxCountInstances': null, 'initialCount': 0},
+ 'commands': {},
+ 'volumeGroupAllowed': true,
+ 'inputs': {
+ '2017488_adiodvpe0_vnf_config_template_version': {
+ 'type': 'string',
+ 'description': 'VPE Software Version',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': '17.2'
+ },
+ '2017488_adiodvpe0_AIC_CLLI': {
+ 'type': 'string',
+ 'description': 'AIC Site CLLI',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': 'ATLMY8GA'
+ }
+ }
+ };
+ }
+
+ function generateVFModule2() {
+ return {
+ 'uuid': '0a0dd9d4-31d3-4c3a-ae89-a02f383e6a9a',
+ 'invariantUuid': 'eff8cc59-53a1-4101-aed7-8cf24ecf8339',
+ 'customizationUuid': '3cd946bb-50e0-40d8-96d3-c9023520b557',
+ 'description': null,
+ 'name': '2017488AdiodVpe..ADIOD_vPFE_BV..module-2',
+ 'version': '6',
+ 'modelCustomizationName': '2017488AdiodVpe..ADIOD_vPFE_BV..module-2',
+ 'properties': {'minCountInstances': 0, 'maxCountInstances': null, 'initialCount': 0},
+ 'commands': {},
+ 'volumeGroupAllowed': true,
+ 'inputs': {}
+ };
+ }
+
+ function generateVNF() {
+ return {
+ 'uuid': '0903e1c0-8e03-4936-b5c2-260653b96413',
+ 'invariantUuid': '00beb8f9-6d39-452f-816d-c709b9cbb87d',
+ 'description': 'Name ADIOD vPE Description The provider edge function for the ADIOD service supported by the Junipers VMX product Category Router Vendor Juniper Vendor Release Code 17.2 Owners Mary Fragale. Updated 9-25 to use v8.0 of the Juniper Valid 2 VLM',
+ 'name': '2017-388_ADIOD-vPE',
+ 'version': '1.0',
+ 'customizationUuid': '280dec31-f16d-488b-9668-4aae55d6648a',
+ 'inputs': {
+ 'vnf_config_template_version': {
+ 'type': 'string',
+ 'description': 'VPE Software Version',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': '17.2'
+ },
+ 'bandwidth_units': {
+ 'type': 'string',
+ 'description': 'Units of bandwidth',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': 'Gbps'
+ },
+ 'bandwidth': {
+ 'type': 'string',
+ 'description': 'Requested VPE bandwidth',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': '10'
+ },
+ 'AIC_CLLI': {
+ 'type': 'string',
+ 'description': 'AIC Site CLLI',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': 'ATLMY8GA'
+ },
+ 'ASN': {
+ 'type': 'string',
+ 'description': 'AV/PE',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': 'AV_vPE'
+ },
+ 'vnf_instance_name': {
+ 'type': 'string',
+ 'description': 'The hostname assigned to the vpe.',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': 'mtnj309me6'
+ }
+ },
+ 'commands': {
+ 'vnf_config_template_version': {
+ 'displayName': 'vnf_config_template_version',
+ 'command': 'get_input',
+ 'inputName': '2017488_adiodvpe0_vnf_config_template_version'
+ },
+ 'bandwidth_units': {
+ 'displayName': 'bandwidth_units',
+ 'command': 'get_input',
+ 'inputName': 'adiodvpe0_bandwidth_units'
+ },
+ 'bandwidth': {'displayName': 'bandwidth', 'command': 'get_input', 'inputName': 'adiodvpe0_bandwidth'},
+ 'AIC_CLLI': {'displayName': 'AIC_CLLI', 'command': 'get_input', 'inputName': '2017488_adiodvpe0_AIC_CLLI'},
+ 'ASN': {'displayName': 'ASN', 'command': 'get_input', 'inputName': '2017488_adiodvpe0_ASN'},
+ 'vnf_instance_name': {
+ 'displayName': 'vnf_instance_name',
+ 'command': 'get_input',
+ 'inputName': '2017488_adiodvpe0_vnf_instance_name'
+ }
+ },
+ 'properties': {
+ 'vmxvre_retype': 'RE-VMX',
+ 'vnf_config_template_version': 'get_input:2017488_adiodvpe0_vnf_config_template_version',
+ 'sriov44_net_id': '48d399b3-11ee-48a8-94d2-f0ea94d6be8d',
+ 'int_ctl_net_id': '2f323477-6936-4d01-ac53-d849430281d9',
+ 'vmxvpfe_sriov41_0_port_mac': '00:11:22:EF:AC:DF',
+ 'int_ctl_net_name': 'VMX-INTXI',
+ 'vmx_int_ctl_prefix': '128.0.0.0',
+ 'sriov43_net_id': 'da349ca1-6de9-4548-be88-2d88e99bfef5',
+ 'sriov42_net_id': '760669ba-013d-4d9b-b0e7-4151fe2e6279',
+ 'sriov41_net_id': '25ad52d5-c165-40f8-b3b0-ddfc2373280a',
+ 'nf_type': 'vPE',
+ 'vmxvpfe_int_ctl_ip_1': '128.0.0.16',
+ 'is_AVPN_service': 'false',
+ 'vmx_RSG_name': 'vREXI-affinity',
+ 'vmx_int_ctl_forwarding': 'l2',
+ 'vmxvre_oam_ip_0': '10.40.123.5',
+ 'vmxvpfe_sriov44_0_port_mac': '00:11:22:EF:AC:DF',
+ 'vmxvpfe_sriov41_0_port_vlanstrip': 'false',
+ 'vmxvpfe_sriov42_0_port_vlanfilter': '4001',
+ 'vmxvpfe_sriov44_0_port_unknownunicastallow': 'true',
+ 'vmxvre_image_name_0': 'VRE-ENGINE_17.2-S2.1.qcow2',
+ 'vmxvre_instance': '0',
+ 'vmxvpfe_sriov43_0_port_mac': '00:11:22:EF:AC:DF',
+ 'vmxvre_flavor_name': 'ns.c1r16d32.v5',
+ 'vmxvpfe_volume_size_0': '40.0',
+ 'vmxvpfe_sriov43_0_port_vlanfilter': '4001',
+ 'nf_naming': '{ecomp_generated_naming=true}',
+ 'nf_naming_code': 'Navneet',
+ 'vmxvre_name_0': 'vREXI',
+ 'vmxvpfe_sriov42_0_port_vlanstrip': 'false',
+ 'vmxvpfe_volume_name_0': 'vPFEXI_FBVolume',
+ 'vmx_RSG_id': 'bd89a33c-13c3-4a04-8fde-1a57eb123141',
+ 'vmxvpfe_image_name_0': 'VPE_ROUTING-ENGINE_17.2R1-S2.1.qcow2',
+ 'vmxvpfe_sriov43_0_port_unknownunicastallow': 'true',
+ 'vmxvpfe_sriov44_0_port_unknownmulticastallow': 'true',
+ 'vmxvre_console': 'vidconsole',
+ 'vmxvpfe_sriov44_0_port_vlanfilter': '4001',
+ 'vmxvpfe_sriov42_0_port_mac': '00:11:22:EF:AC:DF',
+ 'vmxvpfe_volume_id_0': '47cede15-da2f-4397-a101-aa683220aff3',
+ 'vmxvpfe_sriov42_0_port_unknownmulticastallow': 'true',
+ 'vmxvpfe_sriov44_0_port_vlanstrip': 'false',
+ 'vf_module_id': '123',
+ 'nf_function': 'JAI',
+ 'vmxvpfe_sriov43_0_port_unknownmulticastallow': 'true',
+ 'vmxvre_int_ctl_ip_0': '128.0.0.1',
+ 'AIC_CLLI': 'get_input:2017488_adiodvpe0_AIC_CLLI',
+ 'vnf_name': 'mtnj309me6vre',
+ 'vmxvpfe_sriov41_0_port_unknownunicastallow': 'true',
+ 'vmxvre_volume_type_1': 'HITACHI',
+ 'vmxvpfe_sriov44_0_port_broadcastallow': 'true',
+ 'vmxvre_volume_type_0': 'HITACHI',
+ 'vmxvpfe_volume_type_0': 'HITACHI',
+ 'vmxvpfe_sriov43_0_port_broadcastallow': 'true',
+ 'bandwidth_units': 'get_input:adiodvpe0_bandwidth_units',
+ 'vnf_id': '123',
+ 'vmxvre_oam_prefix': '24',
+ 'availability_zone_0': 'mtpocfo-kvm-az01',
+ 'ASN': 'get_input:2017488_adiodvpe0_ASN',
+ 'vmxvre_chassis_i2cid': '161',
+ 'vmxvpfe_name_0': 'vPFEXI',
+ 'bandwidth': 'get_input:adiodvpe0_bandwidth',
+ 'availability_zone_max_count': '1',
+ 'vmxvre_volume_size_0': '45.0',
+ 'vmxvre_volume_size_1': '50.0',
+ 'vmxvpfe_sriov42_0_port_broadcastallow': 'true',
+ 'vmxvre_oam_gateway': '10.40.123.1',
+ 'vmxvre_volume_name_1': 'vREXI_FAVolume',
+ 'vmxvre_ore_present': '0',
+ 'vmxvre_volume_name_0': 'vREXI_FBVolume',
+ 'vmxvre_type': '0',
+ 'vnf_instance_name': 'get_input:2017488_adiodvpe0_vnf_instance_name',
+ 'vmxvpfe_sriov41_0_port_unknownmulticastallow': 'true',
+ 'oam_net_id': 'b95eeb1d-d55d-4827-abb4-8ebb94941429',
+ 'vmx_int_ctl_len': '24',
+ 'vmxvpfe_sriov43_0_port_vlanstrip': 'false',
+ 'vmxvpfe_sriov41_0_port_broadcastallow': 'true',
+ 'vmxvre_volume_id_1': '6e86797e-03cd-4fdc-ba72-2957119c746d',
+ 'vmxvpfe_sriov41_0_port_vlanfilter': '4001',
+ 'nf_role': 'Testing',
+ 'vmxvre_volume_id_0': 'f4eacb79-f687-4e9d-b760-21847c8bb15a',
+ 'vmxvpfe_sriov42_0_port_unknownunicastallow': 'true',
+ 'vmxvpfe_flavor_name': 'ns.c20r16d25.v5'
+ },
+ 'type': 'VF',
+ 'modelCustomizationName': '2017-388_ADIOD-vPE 1',
+ 'vfModules': {},
+ 'volumeGroups': {}
+ };
+ }
+
+ function generateVNF_ecompNamingFalse() {
+ return {
+ 'uuid': '0903e1c0-8e03-4936-b5c2-260653b96413',
+ 'invariantUuid': '00beb8f9-6d39-452f-816d-c709b9cbb87d',
+ 'description': 'Name ADIOD vPE Description The provider edge function for the ADIOD service supported by the Junipers VMX product Category Router Vendor Juniper Vendor Release Code 17.2 Owners Mary Fragale. Updated 9-25 to use v8.0 of the Juniper Valid 2 VLM',
+ 'name': '2017-388_ADIOD-vPE',
+ 'version': '1.0',
+ 'customizationUuid': '280dec31-f16d-488b-9668-4aae55d6648a',
+ 'inputs': {
+ 'vnf_config_template_version': {
+ 'type': 'string',
+ 'description': 'VPE Software Version',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': '17.2'
+ },
+ 'bandwidth_units': {
+ 'type': 'string',
+ 'description': 'Units of bandwidth',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': 'Gbps'
+ },
+ 'bandwidth': {
+ 'type': 'string',
+ 'description': 'Requested VPE bandwidth',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': '10'
+ },
+ 'AIC_CLLI': {
+ 'type': 'string',
+ 'description': 'AIC Site CLLI',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': 'ATLMY8GA'
+ },
+ 'ASN': {
+ 'type': 'string',
+ 'description': 'AV/PE',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': 'AV_vPE'
+ },
+ 'vnf_instance_name': {
+ 'type': 'string',
+ 'description': 'The hostname assigned to the vpe.',
+ 'entry_schema': null,
+ 'constraints': [],
+ 'required': true,
+ 'default': 'mtnj309me6'
+ }
+ },
+ 'commands': {
+ 'vnf_config_template_version': {
+ 'displayName': 'vnf_config_template_version',
+ 'command': 'get_input',
+ 'inputName': '2017488_adiodvpe0_vnf_config_template_version'
+ },
+ 'bandwidth_units': {
+ 'displayName': 'bandwidth_units',
+ 'command': 'get_input',
+ 'inputName': 'adiodvpe0_bandwidth_units'
+ },
+ 'bandwidth': {'displayName': 'bandwidth', 'command': 'get_input', 'inputName': 'adiodvpe0_bandwidth'},
+ 'AIC_CLLI': {'displayName': 'AIC_CLLI', 'command': 'get_input', 'inputName': '2017488_adiodvpe0_AIC_CLLI'},
+ 'ASN': {'displayName': 'ASN', 'command': 'get_input', 'inputName': '2017488_adiodvpe0_ASN'},
+ 'vnf_instance_name': {
+ 'displayName': 'vnf_instance_name',
+ 'command': 'get_input',
+ 'inputName': '2017488_adiodvpe0_vnf_instance_name'
+ }
+ },
+ 'properties': {
+ 'ecomp_generated_naming': "false",
+ 'vmxvre_retype': 'RE-VMX',
+ 'vnf_config_template_version': 'get_input:2017488_adiodvpe0_vnf_config_template_version',
+ 'sriov44_net_id': '48d399b3-11ee-48a8-94d2-f0ea94d6be8d',
+ 'int_ctl_net_id': '2f323477-6936-4d01-ac53-d849430281d9',
+ 'vmxvpfe_sriov41_0_port_mac': '00:11:22:EF:AC:DF',
+ 'int_ctl_net_name': 'VMX-INTXI',
+ 'vmx_int_ctl_prefix': '128.0.0.0',
+ 'sriov43_net_id': 'da349ca1-6de9-4548-be88-2d88e99bfef5',
+ 'sriov42_net_id': '760669ba-013d-4d9b-b0e7-4151fe2e6279',
+ 'sriov41_net_id': '25ad52d5-c165-40f8-b3b0-ddfc2373280a',
+ 'nf_type': 'vPE',
+ 'vmxvpfe_int_ctl_ip_1': '128.0.0.16',
+ 'is_AVPN_service': 'false',
+ 'vmx_RSG_name': 'vREXI-affinity',
+ 'vmx_int_ctl_forwarding': 'l2',
+ 'vmxvre_oam_ip_0': '10.40.123.5',
+ 'vmxvpfe_sriov44_0_port_mac': '00:11:22:EF:AC:DF',
+ 'vmxvpfe_sriov41_0_port_vlanstrip': 'false',
+ 'vmxvpfe_sriov42_0_port_vlanfilter': '4001',
+ 'vmxvpfe_sriov44_0_port_unknownunicastallow': 'true',
+ 'vmxvre_image_name_0': 'VRE-ENGINE_17.2-S2.1.qcow2',
+ 'vmxvre_instance': '0',
+ 'vmxvpfe_sriov43_0_port_mac': '00:11:22:EF:AC:DF',
+ 'vmxvre_flavor_name': 'ns.c1r16d32.v5',
+ 'vmxvpfe_volume_size_0': '40.0',
+ 'vmxvpfe_sriov43_0_port_vlanfilter': '4001',
+ 'nf_naming': '{ecomp_generated_naming=false}',
+ 'nf_naming_code': 'Navneet',
+ 'vmxvre_name_0': 'vREXI',
+ 'vmxvpfe_sriov42_0_port_vlanstrip': 'false',
+ 'vmxvpfe_volume_name_0': 'vPFEXI_FBVolume',
+ 'vmx_RSG_id': 'bd89a33c-13c3-4a04-8fde-1a57eb123141',
+ 'vmxvpfe_image_name_0': 'VPE_ROUTING-ENGINE_17.2R1-S2.1.qcow2',
+ 'vmxvpfe_sriov43_0_port_unknownunicastallow': 'true',
+ 'vmxvpfe_sriov44_0_port_unknownmulticastallow': 'true',
+ 'vmxvre_console': 'vidconsole',
+ 'vmxvpfe_sriov44_0_port_vlanfilter': '4001',
+ 'vmxvpfe_sriov42_0_port_mac': '00:11:22:EF:AC:DF',
+ 'vmxvpfe_volume_id_0': '47cede15-da2f-4397-a101-aa683220aff3',
+ 'vmxvpfe_sriov42_0_port_unknownmulticastallow': 'true',
+ 'vmxvpfe_sriov44_0_port_vlanstrip': 'false',
+ 'vf_module_id': '123',
+ 'nf_function': 'JAI',
+ 'vmxvpfe_sriov43_0_port_unknownmulticastallow': 'true',
+ 'vmxvre_int_ctl_ip_0': '128.0.0.1',
+ 'AIC_CLLI': 'get_input:2017488_adiodvpe0_AIC_CLLI',
+ 'vnf_name': 'mtnj309me6vre',
+ 'vmxvpfe_sriov41_0_port_unknownunicastallow': 'true',
+ 'vmxvre_volume_type_1': 'HITACHI',
+ 'vmxvpfe_sriov44_0_port_broadcastallow': 'true',
+ 'vmxvre_volume_type_0': 'HITACHI',
+ 'vmxvpfe_volume_type_0': 'HITACHI',
+ 'vmxvpfe_sriov43_0_port_broadcastallow': 'true',
+ 'bandwidth_units': 'get_input:adiodvpe0_bandwidth_units',
+ 'vnf_id': '123',
+ 'vmxvre_oam_prefix': '24',
+ 'availability_zone_0': 'mtpocfo-kvm-az01',
+ 'ASN': 'get_input:2017488_adiodvpe0_ASN',
+ 'vmxvre_chassis_i2cid': '161',
+ 'vmxvpfe_name_0': 'vPFEXI',
+ 'bandwidth': 'get_input:adiodvpe0_bandwidth',
+ 'availability_zone_max_count': '1',
+ 'vmxvre_volume_size_0': '45.0',
+ 'vmxvre_volume_size_1': '50.0',
+ 'vmxvpfe_sriov42_0_port_broadcastallow': 'true',
+ 'vmxvre_oam_gateway': '10.40.123.1',
+ 'vmxvre_volume_name_1': 'vREXI_FAVolume',
+ 'vmxvre_ore_present': '0',
+ 'vmxvre_volume_name_0': 'vREXI_FBVolume',
+ 'vmxvre_type': '0',
+ 'vnf_instance_name': 'get_input:2017488_adiodvpe0_vnf_instance_name',
+ 'vmxvpfe_sriov41_0_port_unknownmulticastallow': 'true',
+ 'oam_net_id': 'b95eeb1d-d55d-4827-abb4-8ebb94941429',
+ 'vmx_int_ctl_len': '24',
+ 'vmxvpfe_sriov43_0_port_vlanstrip': 'false',
+ 'vmxvpfe_sriov41_0_port_broadcastallow': 'true',
+ 'vmxvre_volume_id_1': '6e86797e-03cd-4fdc-ba72-2957119c746d',
+ 'vmxvpfe_sriov41_0_port_vlanfilter': '4001',
+ 'nf_role': 'Testing',
+ 'vmxvre_volume_id_0': 'f4eacb79-f687-4e9d-b760-21847c8bb15a',
+ 'vmxvpfe_sriov42_0_port_unknownunicastallow': 'true',
+ 'vmxvpfe_flavor_name': 'ns.c20r16d25.v5'
+ },
+ 'type': 'VF',
+ 'modelCustomizationName': '2017-388_ADIOD-vPE 1',
+ 'vfModules': {},
+ 'volumeGroups': {}
+ };
+ }
+
+});
+
+
+
+
diff --git a/vid-webpack-master/src/app/services/service-planning.service.ts b/vid-webpack-master/src/app/services/service-planning.service.ts
new file mode 100644
index 000000000..75720c8a1
--- /dev/null
+++ b/vid-webpack-master/src/app/services/service-planning.service.ts
@@ -0,0 +1,282 @@
+import {Injectable} from '@angular/core';
+import {Constants} from "../shared/utils/constants";
+import {Utils} from "../utils/utils";
+import * as _ from 'lodash';
+import Parameter = Constants.Parameter;
+import {ITreeNode} from "angular-tree-component/dist/defs/api";
+import {ServiceInstance} from "../shared/models/serviceInstance";
+import {VNFModel} from "../shared/models/vnfModel";
+import {ServiceNodeTypes} from "../shared/models/ServiceNodeTypes";
+import {VfModuleMap} from "../shared/models/vfModulesMap";
+import {VnfInstance} from "../shared/models/vnfInstance";
+import {VfModuleTreeNode} from "../shared/models/vfModuleTreeNode";
+import {VfModule} from "../shared/models/vfModule";
+import {VnfTreeNode} from "../shared/models/vnfTreeNode";
+import {NgRedux} from "@angular-redux/store";
+import {AppState} from "../store/reducers";
+import {InputType} from "../shared/models/inputTypes";
+
+
+@Injectable()
+export class ServicePlanningService {
+
+ modelDataTree: any[] = [];
+ drawingDataTree: any[] = [];
+ service: any = {name:'My Service'} ;
+ public requiredFields = {
+ VF: [InputType.LCP_REGION, InputType.TENANT, InputType.PLATFORM],
+ VFmodule: []
+ };
+
+ constructor(private store: NgRedux<AppState>) {}
+
+
+ public getServiceName() :string{
+ return this.service.name;
+ }
+
+ public getServiceInstance(serviceModelId): ServiceInstance {
+ return this.store.getState().service.serviceInstance[serviceModelId];
+ }
+
+ public getVnfInstance(serviceModelId, vnfModelName): VnfInstance {
+ return this.getServiceInstance(serviceModelId).vnfs[vnfModelName];
+ }
+
+ public getVfModuleMap(serviceModelId, vnfModelName, vfModuleModelName): VfModuleMap {
+ let vnfInstance = this.getVnfInstance(serviceModelId, vnfModelName);
+ return _.get(vnfInstance, ['vfModules', vfModuleModelName]);
+ }
+
+ public convertServiceModelToTreeNodes(serviceModel) {
+ let _this = this;
+
+ _.forOwn(serviceModel.vnfs, function(item, key) {
+ _this.addFirstLevelModel(key, item, item.type, serviceModel);
+ });
+
+ _.forOwn(serviceModel.configurations, function(item, key) {
+ _this.addFirstLevelModel(key, item, ServiceNodeTypes.Configuration, serviceModel);
+ });
+
+ _.forOwn(serviceModel.networks, function(network, key) {
+ _this.addFirstLevelModel(key, network, ServiceNodeTypes.Network, serviceModel);
+ });
+
+ return this.modelDataTree;
+ }
+
+ private addFirstLevelModel(key, value, valueType, serviceModel) {
+
+ let node = this.convertItemToTreeNode(key, value, valueType, null, false);
+ let vnfInstance = this.getVnfInstance(serviceModel.service.uuid, key);
+ if(value.vfModules) {
+ node.children = Object.keys(value.vfModules).map((vmKey) =>
+ this.convertItemToTreeNode(vmKey, value.vfModules[vmKey], ServiceNodeTypes.VFmodule, value, !vnfInstance));
+ }
+ this.modelDataTree.push(node);
+ }
+
+ private convertItemToTreeNode(key, value, valueType, parentModel , disabled) {
+
+ return {
+ id: value.uuid,
+ name: key,
+ tooltip: valueType,
+ type: valueType,
+ count: value.count || 0,
+ max: value.max || 1,
+ children: [],
+ disabled: disabled,
+ dynamicInputs: this.updateDynamicInputsVnfDataFromModel(valueType, value),
+ userProvidedNaming: this.isUserProvidedNaming(valueType, value, parentModel)
+ }
+ }
+
+ public convertServiceInstanceToTreeData(serviceInstance: ServiceInstance, modelId: string): any {
+ let drawingBoardData = [];
+ let _this = this;
+ _.forOwn(serviceInstance.vnfs, (vnfInstance, vnfModelName) => {
+ let vnfModel: VNFModel = _this.store.getState().service.serviceHierarchy[modelId].vnfs[vnfModelName];
+ let vnfNode = new VnfTreeNode(vnfInstance, vnfModel);
+
+ let vfModuleNodes = [];
+ _.forOwn(vnfInstance.vfModules, (vfModuleMap, vfModuleModelName) => {
+ _.forOwn(vfModuleMap, (vfModuleInstance, vfModuleInstsanceName) => {
+ let vfModule: VfModule = _this.store.getState().service.serviceHierarchy[modelId].vnfs[vnfModelName].vfModules[vfModuleModelName];
+ let vfModuleNode: VfModuleTreeNode = new VfModuleTreeNode(vfModuleInstance, vfModule, vfModuleModelName);
+ vfModuleNodes.push(vfModuleNode);
+ });
+ });
+ vnfNode.children = vfModuleNodes;
+ drawingBoardData.push(vnfNode);
+ });
+
+ return drawingBoardData;
+ }
+
+ public getArbitraryInputs(inputs) {
+ let parameter;
+ let parameterList = [];
+ for (let key in inputs) {
+ parameter = {
+ id : key,
+ type : Parameter.STRING,
+ name : key,
+ value : inputs[key][Parameter.DEFAULT],
+ isRequired : inputs[key][Parameter.REQUIRED],
+ description : inputs[key][Parameter.DESCRIPTION]
+ };
+ switch (inputs[key][Parameter.TYPE]) {
+ case Parameter.INTEGER:
+ parameter.type = Parameter.NUMBER;
+ break;
+ case Parameter.BOOLEAN:
+ parameter.type = Parameter.BOOLEAN;
+ break;
+ case Parameter.RANGE:
+ break;
+ case Parameter.LIST:
+ parameter.type = Parameter.LIST;
+ break;
+ case Parameter.MAP:
+ parameter.type = Parameter.MAP;
+ break;
+ }
+ if ( Utils.hasContents(inputs[key][Parameter.CONSTRAINTS])
+ && ( inputs[key][Parameter.CONSTRAINTS].length > 0 ) ) {
+ let constraintsArray = inputs[key][Parameter.CONSTRAINTS];
+ this.addConstraintParameters (parameterList, constraintsArray, key, inputs, parameter);
+ }
+ else {
+
+ parameterList.push(parameter);
+ }
+ }
+ return parameterList;
+ }
+
+ private addConstraintParameters(parameterList, constraintsArray, key, inputs, parameter) {
+ // If there are constraints and the operator is "valid_values",
+ // use a select parameter type.
+ let i:number = constraintsArray.length;
+ let parameterPushed: boolean = false;
+ if ( i > 0 ) {
+ while ( (i--) && (!parameterPushed) ) {
+ let keys = Object.keys(constraintsArray[i]);
+ for ( let operator in keys ) {
+ switch (keys[operator]) {
+ case Parameter.VALID_VALUES:
+ let j: number = constraintsArray[i][Parameter.VALID_VALUES].length;
+ if ( j > 0 ) {
+ let oList = [];
+ let option;
+ while (j--) {
+ option = {
+ name: constraintsArray[i][Parameter.VALID_VALUES][j],
+ isDefault: false
+ };
+ if ( (Utils.hasContents (inputs[key][Parameter.DEFAULT]) )
+ && (inputs[key][Parameter.DEFAULT] === constraintsArray[i][Parameter.VALID_VALUES][j] ) ) {
+ option = {
+ name: constraintsArray[i][Parameter.VALID_VALUES][j],
+ isDefault: true
+ }
+ }
+ oList.push(option);
+ }
+ parameter.type = Parameter.SELECT;
+ parameter.optionList = oList;
+ parameterList.push(parameter);
+ parameterPushed = true;
+ }
+ break;
+
+ case Parameter.EQUAL:
+ if ( constraintsArray[i][Parameter.EQUAL] != null ) {
+ //override parameter type
+ parameter.type = Parameter.STRING;
+ parameter.isReadOnly = true;
+ parameter.value = constraintsArray[i][Parameter.EQUAL];
+ parameterList.push(parameter);
+ parameterPushed = true;
+ }
+ break;
+
+ case Parameter.LENGTH:
+ if ( constraintsArray[i][Parameter.LENGTH] != null ) {
+ parameter.minLength = constraintsArray[i][Parameter.LENGTH];
+ parameter.maxLength = constraintsArray[i][Parameter.LENGTH];
+ parameterList.push(parameter);
+ parameterPushed = true;
+ }
+ break;
+ case Parameter.MAX_LENGTH:
+ if ( constraintsArray[i][Parameter.MAX_LENGTH] != null ) {
+ parameter.maxLength = constraintsArray[i][Parameter.MAX_LENGTH];
+ parameterList.push(parameter);
+ parameterPushed = true;
+ }
+ break;
+ case Parameter.MIN_LENGTH:
+ if ( constraintsArray[i][Parameter.MIN_LENGTH] != null ) {
+ parameter.minLength = constraintsArray[i][Parameter.MIN_LENGTH];
+ parameterList.push(parameter);
+ parameterPushed = true;
+ }
+ break;
+ case Parameter.IN_RANGE:
+ if ( constraintsArray[i][Parameter.IN_RANGE] != null ) {
+ if (constraintsArray[i][Parameter.IN_RANGE].length > 1 ) {
+ parameter.min = constraintsArray[i][Parameter.IN_RANGE][0];
+ parameter.max = constraintsArray[i][Parameter.IN_RANGE][1];
+ parameter.type = Parameter.NUMBER;
+ parameter.value = inputs[key][Parameter.DEFAULT];
+ parameterList.push(parameter);
+ parameterPushed = true;
+ }
+ }
+ break;
+ case Parameter.GREATER_THAN:
+ if ( constraintsArray[i][Parameter.GREATER_THAN] != null ) {
+ parameter.type = Parameter.NUMBER;
+ parameter.min = constraintsArray[i][Parameter.GREATER_THAN];
+ parameter.value = inputs[key][Parameter.DEFAULT];
+ parameterList.push(parameter);
+ parameterPushed = true;
+ }
+ break;
+ }//switch
+ }//for
+ }//while
+ }//if
+ };
+
+ public static isVfModule(node:ITreeNode): boolean {
+ return node.data.type=='VFmodule';
+ }
+
+ public static isVnf(node:ITreeNode): boolean {
+ return node.data.type == ServiceNodeTypes.VF;
+ }
+
+ updateDynamicInputsVnfDataFromModel(modelType: string, model: any): Array<any> {
+ let displayInputs;
+ if (modelType === ServiceNodeTypes.VFmodule) {
+ displayInputs = model.inputs;
+ }
+ return _.isEmpty(displayInputs) ? [] : this.getArbitraryInputs(displayInputs);
+ }
+
+ isUserProvidedNaming(type: string, nodeModel: any, parentModel: any) : boolean {
+ let model;
+ if (type === ServiceNodeTypes.VFmodule) {
+ model = parentModel;
+ }
+ else {
+ model = nodeModel;
+ }
+ const ecompGeneratedNaming = model.properties.ecomp_generated_naming;
+ return ecompGeneratedNaming !== undefined && ecompGeneratedNaming === "false";
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/api.service.ts b/vid-webpack-master/src/app/shared/api.service.ts
new file mode 100644
index 000000000..a69d91ea4
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/api.service.ts
@@ -0,0 +1,6 @@
+import { Injectable } from '@angular/core';
+
+@Injectable()
+export class ApiService {
+ title = 'Angular 2';
+}
diff --git a/vid-webpack-master/src/app/shared/components/ellipsis/ellipsis.component.ts b/vid-webpack-master/src/app/shared/components/ellipsis/ellipsis.component.ts
new file mode 100644
index 000000000..fd58b6507
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/components/ellipsis/ellipsis.component.ts
@@ -0,0 +1,27 @@
+import { Component, Input } from '@angular/core';
+
+@Component({
+ selector : 'custom-ellipsis',
+ template: `
+ <span
+ class="ellipsis"
+ id="{{id}}"
+ tooltip="{{value}}">{{value}}</span>`,
+ styles : [
+ `
+ .ellipsis {
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ display: inline-block;
+ width: 99%;
+ text-align: left;
+ }
+ `
+ ]
+})
+export class EllipsisComponent {
+ @Input() value : string;
+ @Input() id : string;
+
+}
diff --git a/vid-webpack-master/src/app/shared/components/error/error.component.service.ts b/vid-webpack-master/src/app/shared/components/error/error.component.service.ts
new file mode 100644
index 000000000..35b83f0b6
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/components/error/error.component.service.ts
@@ -0,0 +1,35 @@
+import {Injectable} from "@angular/core";
+import {Subject} from "rxjs/Subject";
+import { MessageBoxService } from '../messageBox/messageBox.service';
+import { MessageBoxData, ModalSize, ModalType } from '../messageBox/messageBox.data';
+
+@Injectable()
+export class ErrorService {
+ static showErrorWithMessage(error : ErrorMessage) : void {
+ setTimeout(()=>{
+ let messageBoxData : MessageBoxData = new MessageBoxData(
+ error.title, // modal title
+ error.text,
+
+ ModalType.error,
+ ModalSize.medium,
+ [
+ {text:"Close", size:"large", closeModal:true}
+ ]);
+ MessageBoxService.openModal.next(messageBoxData);
+ }
+ ,500);
+ }
+}
+
+export class ErrorMessage {
+ title : string;
+ text : string;
+ errorNumber : number;
+
+ constructor( title : string, text : string,errorNumber : number){
+ this.title = title;
+ this.text = text;
+ this.errorNumber = errorNumber;
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/components/formControlError/formControlError.component.html b/vid-webpack-master/src/app/shared/components/formControlError/formControlError.component.html
new file mode 100644
index 000000000..daa35e659
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/components/formControlError/formControlError.component.html
@@ -0,0 +1,4 @@
+<div *ngIf="message">
+ <span class="icon-alert"></span>
+ <span class="message">{{message}}</span>
+</div>
diff --git a/vid-webpack-master/src/app/shared/components/formControlError/formControlError.component.scss b/vid-webpack-master/src/app/shared/components/formControlError/formControlError.component.scss
new file mode 100644
index 000000000..d174f511c
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/components/formControlError/formControlError.component.scss
@@ -0,0 +1,14 @@
+.icon-alert {
+ margin-top: 10px;
+ &:before {
+ content: "\e904";
+ font-size: 16px;
+ color: #cf2a2a;
+ }
+}
+
+.message {
+ font-size: 12px;
+ line-height: 14px;
+ color: #cf2a2a;
+}
diff --git a/vid-webpack-master/src/app/shared/components/formControlError/formControlError.component.ts b/vid-webpack-master/src/app/shared/components/formControlError/formControlError.component.ts
new file mode 100644
index 000000000..a20b26030
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/components/formControlError/formControlError.component.ts
@@ -0,0 +1,10 @@
+import { Component, Input } from '@angular/core';
+
+@Component({
+ selector : 'form-control-error',
+ templateUrl : 'formControlError.component.html',
+ styleUrls : ['formControlError.component.scss']
+})
+export class FormControlErrorComponent {
+ @Input() message = null;
+}
diff --git a/vid-webpack-master/src/app/shared/components/formGeneralErrors/formGeneralErrors.component.html b/vid-webpack-master/src/app/shared/components/formGeneralErrors/formGeneralErrors.component.html
new file mode 100644
index 000000000..4c794e686
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/components/formGeneralErrors/formGeneralErrors.component.html
@@ -0,0 +1,10 @@
+<div *ngIf="message" class="row row-padding">
+ <div class="col-md-2 icon-div"><span class="icon-alert"></span></div>
+ <div class="col-md-10 left-align parentbox">
+ <div class="childbox">
+ <span>{{message}}</span>
+ </div>
+ </div>
+</div>
+
+
diff --git a/vid-webpack-master/src/app/shared/components/formGeneralErrors/formGeneralErrors.component.scss b/vid-webpack-master/src/app/shared/components/formGeneralErrors/formGeneralErrors.component.scss
new file mode 100644
index 000000000..5271cad49
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/components/formGeneralErrors/formGeneralErrors.component.scss
@@ -0,0 +1,48 @@
+.icon-alert {
+ margin-top: 10px;
+ &:before {
+ content: "\e904";
+ font-size: 30px;
+ color: #ffffff;
+ }
+}
+
+.icon-div {
+ background: rgb(207,41,41);
+ text-align: center;
+ padding-top: 18px;
+ width: 77px;
+ height: 110px;
+ float: left;
+}
+
+
+.error-title {
+ color: #cf2a2a;
+}
+
+.row-padding {
+ margin-left: 0 !important;
+ margin-right: 0 !important;
+}
+
+.left-align {
+ text-align: left;
+}
+
+.parentbox {
+ padding-right: 0;
+}
+
+.parentbox:before {
+ content: ' ';
+ display: inline-block;
+ vertical-align: middle;
+ height: 100%;
+}
+
+.childbox {
+ color: #cf2a2a;
+ display: inline-block;
+ vertical-align: middle;
+}
diff --git a/vid-webpack-master/src/app/shared/components/formGeneralErrors/formGeneralErrors.component.ts b/vid-webpack-master/src/app/shared/components/formGeneralErrors/formGeneralErrors.component.ts
new file mode 100644
index 000000000..0c0516a4d
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/components/formGeneralErrors/formGeneralErrors.component.ts
@@ -0,0 +1,11 @@
+import { Component, Input } from '@angular/core';
+
+@Component({
+ selector : 'form-general-error',
+ templateUrl : 'formGeneralErrors.component.html',
+ styleUrls : ['formGeneralErrors.component.scss']
+})
+
+export class FormGeneralErrorsComponent {
+ @Input() message : string = null;
+}
diff --git a/vid-webpack-master/src/app/shared/components/messageBox/messageBox.component.ts b/vid-webpack-master/src/app/shared/components/messageBox/messageBox.component.ts
new file mode 100644
index 000000000..08e199cf5
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/components/messageBox/messageBox.component.ts
@@ -0,0 +1,50 @@
+/************************************************************************************************
+ * @Component: Message box component
+ * In order to use component you need to do a number of things:
+ * 1) Inside your component constructor you need to add listener to the button trigger.
+ * 2) Inside the listener you should write your callback logic.
+ *
+ * Example:
+ * @Component({
+ * selector : 'some-component'
+ * ...
+ * })
+ *
+ * export class SomeComponent {
+ * openModal() : void {
+ * let messageBoxData : MessageBoxData = new MessageBoxData(
+ * "title", // modal title
+ * "message", ModalType.alert, // modal type
+ * [
+ {text:"Save", size:"'x-small'", callback: this.someFunction.bind(this), closeModal:true},
+ {text:"Cancel", size:"'x-small'", closeModal:true}
+ ]);
+ *
+ * MessageBoxService.openModal.next(messageBoxData); // open modal
+ * }
+ * }
+
+ ************************************************************************************************/
+
+
+import { Component } from '@angular/core';
+import { MessageBoxData} from './messageBox.data';
+import { MessageBoxService } from './messageBox.service';
+import { SdcUiComponents } from 'sdc-ui/lib/angular';
+
+@Component({
+ selector: 'message-box',
+ template: '<div id="message-box"></div>'
+})
+
+export class MessageBoxComponent {
+ modalService: SdcUiComponents.ModalService;
+
+ constructor(modalService: SdcUiComponents.ModalService, private _messageBoxService : MessageBoxService) {
+ this.modalService = modalService;
+ MessageBoxService.openModal.subscribe((messageBoxData: MessageBoxData) => {
+ modalService.openModal(this._messageBoxService.setConfig(messageBoxData))
+ });
+ }
+}
+
diff --git a/vid-webpack-master/src/app/shared/components/messageBox/messageBox.data.ts b/vid-webpack-master/src/app/shared/components/messageBox/messageBox.data.ts
new file mode 100644
index 000000000..165140ba7
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/components/messageBox/messageBox.data.ts
@@ -0,0 +1,51 @@
+import { Subject } from 'rxjs/Subject';
+
+export class MessageBoxData {
+ title?: string;
+ message?: string;
+ size : ModalSize;
+ type: ModalType;
+ buttons: Array<IModalButtonComponent>;
+
+ constructor(title: string, message: string, type: ModalType, size : ModalSize, buttons: Array<IModalButtonComponent>) {
+ this.title = title;
+ this.message = message;
+ this.size = size;
+ this.type = type;
+ this.buttons = buttons;
+ }
+}
+
+export interface IModalConfig {
+ size?: string;
+ title?: string;
+ message?: string;
+ buttons?: Array<IModalButtonComponent>;
+ type?: string;
+}
+export interface IButtonComponent {
+ text: string;
+ disabled?: boolean;
+ type?: string;
+ size?: string;
+}
+export interface IModalButtonComponent extends IButtonComponent {
+ callback?: Function;
+ closeModal?: boolean;
+}
+export enum ModalType {
+ alert = "alert",
+ error = "error",
+ standard = "info",
+ custom = "custom",
+}
+export enum ModalSize {
+ xlarge = "xl",
+ large = "l",
+ medium = "md",
+ small = "sm",
+ xsmall = "xsm",
+}
+
+
+
diff --git a/vid-webpack-master/src/app/shared/components/messageBox/messageBox.service.spec.ts b/vid-webpack-master/src/app/shared/components/messageBox/messageBox.service.spec.ts
new file mode 100644
index 000000000..89562ac54
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/components/messageBox/messageBox.service.spec.ts
@@ -0,0 +1,49 @@
+import { TestBed, getTestBed } from '@angular/core/testing';
+import {
+ HttpClientTestingModule,
+ HttpTestingController
+} from '@angular/common/http/testing';
+
+import { MessageBoxService } from './messageBox.service';
+import {MessageBoxData, ModalSize, ModalType } from './messageBox.data';
+
+describe('MessageBoxService', () => {
+ let injector;
+ let service: MessageBoxService;
+ let httpMock: HttpTestingController;
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({
+ imports: [HttpClientTestingModule],
+ providers: [MessageBoxService]
+ });
+
+ injector = getTestBed();
+ service = injector.get(MessageBoxService);
+ httpMock = injector.get(HttpTestingController);
+ });
+
+ describe('#setConfig', () => {
+ it('should return <IModalConfig>', (done: DoneFn) => {
+ let title = "Delete Instantiation";
+ let message = "You are about to stop the instantiation process of this service. \nAll data will be lost. Are you sure you want to stop?";
+ let messageBoxData : MessageBoxData = new MessageBoxData(
+ title,
+ message,
+ ModalType.alert,
+ ModalSize.medium,
+ [
+ {text:"Stop Instantiation", size:"large", closeModal:true},
+ {text:"Cancel", size:"medium", closeModal:true}
+ ]);
+
+ let result = service.setConfig(messageBoxData);
+ expect(result.title).toEqual(title);
+ expect(result.message).toEqual(message);
+ expect(result.buttons.length).toEqual(2);
+ expect(result.type).toEqual(ModalType.alert);
+ expect(result.size).toEqual(ModalSize.medium);
+ done();
+ });
+ });
+});
diff --git a/vid-webpack-master/src/app/shared/components/messageBox/messageBox.service.ts b/vid-webpack-master/src/app/shared/components/messageBox/messageBox.service.ts
new file mode 100644
index 000000000..eaa012d3b
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/components/messageBox/messageBox.service.ts
@@ -0,0 +1,18 @@
+import { Injectable } from '@angular/core';
+import { Subject } from 'rxjs/Subject';
+import { IModalConfig, MessageBoxData, ModalSize, ModalType } from './messageBox.data';
+
+@Injectable()
+export class MessageBoxService {
+ static openModal: Subject<MessageBoxData> = new Subject<MessageBoxData>();
+ setConfig(messageBoxData: MessageBoxData) : IModalConfig{
+ return {
+ size : ModalSize.medium,
+ title : messageBoxData.title,
+ type : messageBoxData.type,
+ message : messageBoxData.message,
+ buttons: messageBoxData.buttons
+ };
+ }
+
+}
diff --git a/vid-webpack-master/src/app/shared/components/model-information/model-information.component.ts b/vid-webpack-master/src/app/shared/components/model-information/model-information.component.ts
new file mode 100644
index 000000000..fea4c44c7
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/components/model-information/model-information.component.ts
@@ -0,0 +1,42 @@
+import {Component, Input} from '@angular/core';
+import * as _ from 'lodash';
+
+@Component({
+ selector: 'model-information',
+ templateUrl: 'model-information.html',
+ styleUrls: ['model-information.scss']
+})
+
+export class ModelInformationComponent {
+ private _modelInformationItems: Array<ModelInformationItem>;
+
+
+ get modelInformationItems(): Array<ModelInformationItem> {
+ return this._modelInformationItems;
+ }
+
+ @Input()
+ set modelInformationItems(_modelInformationItems: Array<ModelInformationItem>) {
+ if (_modelInformationItems) {
+ this._modelInformationItems = _modelInformationItems.filter(x => x.mandatory || (!_.isEmpty(x.values) && !_.isEmpty(x.values[0])));
+ }
+ }
+}
+
+
+export class ModelInformationItem {
+ label: string;
+ testsId: string;
+ values: Array<string>;
+ toolTipText: string;
+ mandatory: boolean;
+
+ constructor(label: string, testsId: string, values: Array<any>, toolTipText: string = "", mandatory: boolean = false,nested:boolean=false) {
+ this.label = label;
+ this.testsId = testsId;
+ this.values = values;
+ this.toolTipText = toolTipText;
+ this.mandatory = mandatory;
+ }
+
+}
diff --git a/vid-webpack-master/src/app/shared/components/model-information/model-information.html b/vid-webpack-master/src/app/shared/components/model-information/model-information.html
new file mode 100644
index 000000000..456dfdee4
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/components/model-information/model-information.html
@@ -0,0 +1,12 @@
+<div id="model-information">
+ <div *ngFor="let item of modelInformationItems" class="item" attr.data-tests-id="model-item-{{item.label}}">
+ <tooltip-content #a>
+ <span> {{item.toolTipText}}</span>
+ </tooltip-content>
+
+ <div class="wrapper" [tooltip]="a" [tooltipDisabled]="!item.toolTipText" tooltipPlacement="top" [tooltipAnimation]="false">
+ <label attr.data-tests-id="model-item-label-{{item.testsId}}">{{item.label}}</label>
+ <div *ngFor="let value of item.values" attr.data-tests-id="model-item-value-{{item.testsId}}">{{value}}</div>
+ </div>
+ </div>
+</div>
diff --git a/vid-webpack-master/src/app/shared/components/model-information/model-information.scss b/vid-webpack-master/src/app/shared/components/model-information/model-information.scss
new file mode 100644
index 000000000..cd42136ed
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/components/model-information/model-information.scss
@@ -0,0 +1,34 @@
+#model-information {
+ overflow: auto;
+
+}
+
+tooltip-content span {
+ font-family: OpenSans-Regular;
+ font-size: 12px;
+ color: #FFFFFF;
+ letter-spacing: 0;
+ line-height: 16px;
+}
+
+.item {
+ display: block;
+
+ .wrapper {
+
+ display: inline-block;
+ margin-bottom: 25px;
+
+ label {
+ font-family: OpenSans-Semibold;
+ font-size: 12px;
+ }
+
+ div {
+ font-family: OpenSans-Regular;
+ font-size: 14px;
+ }
+ }
+}
+
+
diff --git a/vid-webpack-master/src/app/shared/components/no-content-message-and-icon/no-content-message-and-icon.component.html b/vid-webpack-master/src/app/shared/components/no-content-message-and-icon/no-content-message-and-icon.component.html
new file mode 100644
index 000000000..bbe7bc78c
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/components/no-content-message-and-icon/no-content-message-and-icon.component.html
@@ -0,0 +1,5 @@
+<div class="width-100">
+ <div class="text-title" [ngClass]="titleClass">{{title}}</div>
+ <div class="text-subtitle" [ngClass]="subtitleClass">{{subtitle}}</div>
+ <img id="not-node-img-id" src="{{iconPath}}" alt="" class="no-content-icon" [ngClass]="iconClass" data-tests-id="no-content-icon">
+</div>
diff --git a/vid-webpack-master/src/app/shared/components/no-content-message-and-icon/no-content-message-and-icon.component.scss b/vid-webpack-master/src/app/shared/components/no-content-message-and-icon/no-content-message-and-icon.component.scss
new file mode 100644
index 000000000..1320ef731
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/components/no-content-message-and-icon/no-content-message-and-icon.component.scss
@@ -0,0 +1,26 @@
+.width-100 {
+ width: 100%;
+ margin-top: 126px;
+
+}
+
+.text-title {
+ font-family: OpenSans-Semibold;
+ font-size: 16px;
+ color: #4A4A4A;
+ text-align: center;
+}
+
+.text-subtitle {
+ font-family: OpenSans-Regular;
+ font-size: 16px;
+ color: #959595;
+ text-align: center;
+ margin-top: 7px;
+}
+
+.no-content-icon {
+ display: block;
+ vertical-align: middle;
+ margin: 30px auto;
+}
diff --git a/vid-webpack-master/src/app/shared/components/no-content-message-and-icon/no-content-message-and-icon.component.ts b/vid-webpack-master/src/app/shared/components/no-content-message-and-icon/no-content-message-and-icon.component.ts
new file mode 100644
index 000000000..7f4e98294
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/components/no-content-message-and-icon/no-content-message-and-icon.component.ts
@@ -0,0 +1,23 @@
+import {Component, Input} from '@angular/core';
+
+@Component({
+ selector: 'no-content-message-and-icon',
+ templateUrl: './no-content-message-and-icon.component.html',
+ styleUrls: ['./no-content-message-and-icon.component.scss']
+})
+
+
+export class NoContentMessageAndIconComponent {
+ constructor() {}
+
+ @Input() title: string;
+ @Input() subtitle: string;
+ @Input() iconPath: string;
+
+ @Input() titleClass: string="";
+ @Input() subtitleClass: string="";
+ @Input() iconClass: string="";
+
+}
+
+
diff --git a/vid-webpack-master/src/app/shared/components/popover/popover.component.html b/vid-webpack-master/src/app/shared/components/popover/popover.component.html
new file mode 100644
index 000000000..c5515596c
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/components/popover/popover.component.html
@@ -0,0 +1,8 @@
+<div
+ triggers="mouseenter:mouseleave"
+ popover="{{value}}"
+ [hidden]="value == null"
+ container="body">
+ <ng-content ></ng-content>
+</div>
+
diff --git a/vid-webpack-master/src/app/shared/components/popover/popover.component.scss b/vid-webpack-master/src/app/shared/components/popover/popover.component.scss
new file mode 100644
index 000000000..ca2800a27
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/components/popover/popover.component.scss
@@ -0,0 +1,4 @@
+.popover.popover-top.top {
+ color : green !important;
+ font-size: 10px;
+}
diff --git a/vid-webpack-master/src/app/shared/components/popover/popover.component.ts b/vid-webpack-master/src/app/shared/components/popover/popover.component.ts
new file mode 100644
index 000000000..d6a4c3ae1
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/components/popover/popover.component.ts
@@ -0,0 +1,17 @@
+import {Component, Input} from "@angular/core";
+
+@Component({
+ selector: 'custom-popover',
+ templateUrl: 'popover.component.html',
+ styles: [`
+ :host >>> .popover {
+ font-size: 13px;
+ text-align: left;
+ z-index: 10000;
+ }
+ `]
+})
+
+export class PopoverComponent {
+ @Input() value: String;
+}
diff --git a/vid-webpack-master/src/app/shared/components/spinner/spinner.component.html b/vid-webpack-master/src/app/shared/components/spinner/spinner.component.html
new file mode 100644
index 000000000..cb11feea8
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/components/spinner/spinner.component.html
@@ -0,0 +1,2 @@
+<div *ngIf="show"
+ class="spinner"></div>
diff --git a/vid-webpack-master/src/app/shared/components/spinner/spinner.component.scss b/vid-webpack-master/src/app/shared/components/spinner/spinner.component.scss
new file mode 100644
index 000000000..d31dfed80
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/components/spinner/spinner.component.scss
@@ -0,0 +1,87 @@
+.spinner {
+ height: 150px;
+ width: 150px;
+ margin: 0 auto;
+ -webkit-animation: rotation .6s infinite linear;
+ animation: rotation .6s infinite linear;
+ border: 6px solid rgba(0, 174, 239, 0.01);
+ border-radius: 100%;
+ position: absolute;
+ z-index: 1000;
+ left: 50%;
+ right: 50%;
+ top: 50%;
+ bottom: 50%;
+}
+
+
+
+.spinner:before {
+ content: "";
+ display: block;
+ position: absolute;
+ top: -6px;
+ height: 100%;
+ width: 100%;
+ border-top: 6px solid #009fdb;
+ border-left: 6px solid transparent;
+ border-bottom: 6px solid #c3161600;
+ border-right: 6px solid transparent;
+ border-radius: 100%;
+}
+
+@-webkit-keyframes rotation {
+ from {-webkit-transform: rotate(0deg);}
+ to {-webkit-transform: rotate(359deg);}
+}
+@-moz-keyframes rotation {
+ from {-moz-transform: rotate(0deg);}
+ to {-moz-transform: rotate(359deg);}
+}
+@-o-keyframes rotation {
+ from {-o-transform: rotate(0deg);}
+ to {-o-transform: rotate(359deg);}
+}
+@keyframes rotation {
+ from {transform: rotate(0deg);}
+ to {transform: rotate(359deg);}
+}
+
+.spinner-sm {
+ height:16px;
+ width:16px;
+}
+
+.spinner-md {
+ height:40px;
+ width:40px;
+}
+
+.spinner-lr {
+ height:150px;
+ width:150px;
+}
+
+.spinner-red {
+ border:6px solid rgba(216, 27, 34, .15);
+}
+
+.spinner-red:before {
+ border-top:6px solid rgba(216, 27, 34, 1);
+}
+
+.spinner-green {
+ border:6px solid rgba(40, 183, 121, .15);
+}
+
+.spinner-green:before {
+ border-top:6px solid rgba(40, 183, 121, 1);
+}
+
+.spinner-grey {
+ border:6px solid rgba(139, 146, 154, .15);
+}
+
+.spinner-grey:before {
+ border-top:6px solid rgba(139, 146, 154, 1);
+}
diff --git a/vid-webpack-master/src/app/shared/components/spinner/spinner.component.spec.ts b/vid-webpack-master/src/app/shared/components/spinner/spinner.component.spec.ts
new file mode 100644
index 000000000..531ee8c62
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/components/spinner/spinner.component.spec.ts
@@ -0,0 +1,42 @@
+import {async, ComponentFixture, TestBed} from '@angular/core/testing';
+import {HttpClientTestingModule} from '@angular/common/http/testing';
+import { SpinnerComponent } from './spinner.component';
+
+describe('Spinner component', () => {
+ let component: SpinnerComponent;
+ let fixture: ComponentFixture<SpinnerComponent>;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ imports: [HttpClientTestingModule],
+ providers: [],
+ declarations: [SpinnerComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(SpinnerComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('component should be defined', () => {
+ expect(component).toBeDefined();
+ });
+
+
+ it('component constructor should subscribe of showSpinner event with true', ()=> {
+ SpinnerComponent.showSpinner.next(true);
+ expect(component.show).toBeTruthy();
+ });
+
+ it('component constructor should subscribe of showSpinner event with false', ()=> {
+ SpinnerComponent.showSpinner.next(false);
+ expect(component.show).toBeFalsy();
+ });
+
+
+
+
+});
diff --git a/vid-webpack-master/src/app/shared/components/spinner/spinner.component.ts b/vid-webpack-master/src/app/shared/components/spinner/spinner.component.ts
new file mode 100644
index 000000000..0ce5d2074
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/components/spinner/spinner.component.ts
@@ -0,0 +1,18 @@
+import { Component, Input } from '@angular/core';
+import { Subject } from 'rxjs/Subject';
+
+@Component({
+ selector : 'spinner-component',
+ templateUrl : './spinner.component.html',
+ styleUrls : ['./spinner.component.scss']
+})
+export class SpinnerComponent {
+ show : boolean = false;
+ static showSpinner: Subject<boolean> = new Subject<boolean>();
+
+ constructor(){
+ SpinnerComponent.showSpinner.subscribe((status) => {
+ this.show = status;
+ })
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/components/validators/numbersLettersUnderscore/numbersLettersUnderscore.validator.spec.ts b/vid-webpack-master/src/app/shared/components/validators/numbersLettersUnderscore/numbersLettersUnderscore.validator.spec.ts
new file mode 100644
index 000000000..ec9f3f73e
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/components/validators/numbersLettersUnderscore/numbersLettersUnderscore.validator.spec.ts
@@ -0,0 +1,39 @@
+import { ReflectiveInjector } from '@angular/core';
+import { NumbersLettersUnderscoreValidator } from './numbersLettersUnderscore.validator';
+
+describe('Numbers letters underscore validator', () => {
+ let injector;
+ let service: NumbersLettersUnderscoreValidator;
+
+ beforeEach(() => {
+
+ let injector = ReflectiveInjector.resolveAndCreate([
+ NumbersLettersUnderscoreValidator
+ ]);
+
+ service = injector.get(NumbersLettersUnderscoreValidator);
+ });
+
+
+ describe('#valid', () => {
+ it("'legal' should return null", ()=> {
+ let legalVal: string = "legal";
+ let result = NumbersLettersUnderscoreValidator.valid(legalVal);
+ expect(result).toBeNull();
+ });
+
+ it("'illegal' should return object with invalidNumberLettersUnderscore true", ()=> {
+ let illegalVal: string = "illegal-Val";
+ let result = NumbersLettersUnderscoreValidator.valid(illegalVal);
+ expect(result.invalidNumberLettersUnderscore).toBeTruthy();
+ });
+
+ it("'null' should return null", ()=> {
+ let nullVal: string = null
+ let result = NumbersLettersUnderscoreValidator.valid(nullVal);
+ expect(result).toBeNull();
+ });
+
+
+ });
+});
diff --git a/vid-webpack-master/src/app/shared/components/validators/numbersLettersUnderscore/numbersLettersUnderscore.validator.ts b/vid-webpack-master/src/app/shared/components/validators/numbersLettersUnderscore/numbersLettersUnderscore.validator.ts
new file mode 100644
index 000000000..418bdfc4d
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/components/validators/numbersLettersUnderscore/numbersLettersUnderscore.validator.ts
@@ -0,0 +1,20 @@
+import { Injectable } from '@angular/core';
+import { isNullOrUndefined, isString } from 'util';
+
+@Injectable()
+export class NumbersLettersUnderscoreValidator {
+ static valid(control: any) {
+ let reg = /^[a-zA-Z0-9_]*$/;
+
+ if(isNullOrUndefined(control)) return null;
+ let val = isString(control) ? control : control.value;
+ if (val === null) {
+ return {'invalidNumberLettersUnderscore': true};
+ }
+ if (reg.test(val)) {
+ return null;
+ } else {
+ return {'invalidNumberLettersUnderscore': true};
+ }
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/directives/inputPrevention/inputPreventionPattern.directive.spec.ts b/vid-webpack-master/src/app/shared/directives/inputPrevention/inputPreventionPattern.directive.spec.ts
new file mode 100644
index 000000000..846ff70f2
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/directives/inputPrevention/inputPreventionPattern.directive.spec.ts
@@ -0,0 +1,66 @@
+import {TestBed, ComponentFixture} from '@angular/core/testing';
+import {Component, DebugElement} from "@angular/core";
+import {By} from "@angular/platform-browser";
+import { InputPreventionPatternDirective } from './inputPreventionPattern.directive';
+
+@Component({
+ template: `<input
+ patternInput
+ pattern="^[a-zA-Z0-9_]*$">`
+})
+class TestHoverFocusComponent {
+}
+
+
+describe('InputPrevention Pattern Directive', () => {
+
+ let component: TestHoverFocusComponent;
+ let fixture: ComponentFixture<TestHoverFocusComponent>;
+ let directiveInstance : InputPreventionPatternDirective;
+ let inputEl: DebugElement;
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({
+ declarations: [TestHoverFocusComponent, InputPreventionPatternDirective]
+ });
+ fixture = TestBed.createComponent(TestHoverFocusComponent);
+ component = fixture.componentInstance;
+ inputEl = fixture.debugElement.query(By.css('input'));
+ directiveInstance = inputEl.injector.get(InputPreventionPatternDirective);
+ });
+
+ it('directive should be defined', () => {
+ expect(directiveInstance).toBeDefined();
+ });
+
+ it('pattern exists', () => {
+ expect(inputEl.nativeElement.pattern).toEqual('^[a-zA-Z0-9_]*$');
+ });
+
+ it('kepress legal input', () => {
+ fixture.detectChanges();
+ inputEl.nativeElement.value = "legalInput";
+ expect(new RegExp(inputEl.nativeElement.pattern).test(inputEl.nativeElement.value)).toBeTruthy();
+ });
+
+ it('kepress illegal input', () => {
+ inputEl.triggerEventHandler('kepress', " ");
+ fixture.detectChanges();
+ expect(inputEl.nativeElement.value).toBe('');
+ });
+
+ it('kepress event legal input should return event', () => {
+ const event = <any>{ key: 'A' };
+ inputEl.nativeElement.value = "legalInput";
+ let result = directiveInstance.onKeypress(event);
+ expect(result).toBe(event);
+ });
+
+ it('kepress event illegal input should prevent default', () => {
+ const event = <any>{key: '-', preventDefault : function () {} };
+ spyOn(event, 'preventDefault');
+ inputEl.nativeElement.value = "-";
+ let result = directiveInstance.onKeypress(event);
+ expect(event.preventDefault).toHaveBeenCalled();
+ });
+});
diff --git a/vid-webpack-master/src/app/shared/directives/inputPrevention/inputPreventionPattern.directive.ts b/vid-webpack-master/src/app/shared/directives/inputPrevention/inputPreventionPattern.directive.ts
new file mode 100644
index 000000000..dada09bef
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/directives/inputPrevention/inputPreventionPattern.directive.ts
@@ -0,0 +1,24 @@
+import {Directive, ElementRef} from '@angular/core';
+
+@Directive({
+ selector: '[patternInput]',
+ host: {
+ '(keypress)': 'onKeypress($event)'
+ }
+})
+export class InputPreventionPatternDirective{
+ inputElement : ElementRef;
+ constructor(el: ElementRef) {
+ this.inputElement = el;
+ }
+
+ onKeypress(event: KeyboardEvent) {
+ const pattern = new RegExp(this.inputElement.nativeElement.pattern);
+ if(pattern){
+ if(!pattern.test(event['key'])){
+ event.preventDefault();
+ }
+ }
+ return event;
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/directives/svg/svg.directive.html b/vid-webpack-master/src/app/shared/directives/svg/svg.directive.html
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/directives/svg/svg.directive.html
diff --git a/vid-webpack-master/src/app/shared/directives/svg/svg.directive.ts b/vid-webpack-master/src/app/shared/directives/svg/svg.directive.ts
new file mode 100644
index 000000000..e4dc55a56
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/directives/svg/svg.directive.ts
@@ -0,0 +1,34 @@
+import { AfterContentChecked, AfterViewInit, Directive, ElementRef, Input } from '@angular/core';
+import { isNullOrUndefined } from 'util';
+
+
+/*
+ Temporary
+ Changing svg color and size.
+ color changing according to fill attribute
+ size according to viewBox
+*/
+@Directive({
+ selector: '[svg-directive]'
+})
+export class SvgDirective implements AfterContentChecked {
+ @Input('fill') fill: string = "black";
+ @Input('widthViewBox') widthViewBox: string = null;
+ @Input('heightViewBox') heightViewBox: string = null;
+
+ constructor(private elRef: ElementRef) {}
+ ngAfterContentChecked(): void {
+ if(this.elRef !== undefined && this.elRef.nativeElement.children !== undefined && this.elRef.nativeElement.children[0] !== undefined){
+ this.elRef.nativeElement.children[0].children[1].children[0].style.fill = this.fill;
+ if(this.elRef.nativeElement.children[0].children[1].children.length > 1){
+ this.elRef.nativeElement.children[0].children[1].children[1].style.fill = this.fill;
+ this.elRef.nativeElement.children[0].children[1].children[2].children[0].style.fill = this.fill;
+ }
+
+ if(this.widthViewBox && this.heightViewBox){
+ this.elRef.nativeElement.firstChild.setAttribute('viewBox', "1 1 " + this.widthViewBox + " " + this.heightViewBox)
+ }
+
+ }
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/index.ts b/vid-webpack-master/src/app/shared/index.ts
new file mode 100644
index 000000000..68fada65d
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/index.ts
@@ -0,0 +1 @@
+export * from './api.service';
diff --git a/vid-webpack-master/src/app/shared/models/ServiceNodeTypes.ts b/vid-webpack-master/src/app/shared/models/ServiceNodeTypes.ts
new file mode 100644
index 000000000..f72b32d8b
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/ServiceNodeTypes.ts
@@ -0,0 +1,8 @@
+export enum ServiceNodeTypes {
+ VF = "VF",
+ VFmodule = "VFmodule",
+ Network = "Network",
+ Configuration = "Configuration"
+}
+
+
diff --git a/vid-webpack-master/src/app/shared/models/aicZone.ts b/vid-webpack-master/src/app/shared/models/aicZone.ts
new file mode 100644
index 000000000..7b9e1ed4e
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/aicZone.ts
@@ -0,0 +1,9 @@
+export class AicZone {
+ id: string;
+ name: string;
+
+ constructor(serviceJson){
+ this.id = serviceJson["zone-id"];
+ this.name = serviceJson["zone-name"];
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/models/categoryParams.ts b/vid-webpack-master/src/app/shared/models/categoryParams.ts
new file mode 100644
index 000000000..9e0052979
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/categoryParams.ts
@@ -0,0 +1,15 @@
+import {SelectOptionInterface} from "./selectOption";
+
+export class CategoryParams {
+ owningEntityList: SelectOptionInterface[];
+ projectList: SelectOptionInterface[];
+ lineOfBusinessList: SelectOptionInterface[];
+ platformList: SelectOptionInterface[];
+
+ constructor(owningEntityList=[], projectList=[], lob=[], platform=[]){
+ this.owningEntityList = owningEntityList;
+ this.projectList = projectList;
+ this.lineOfBusinessList = lob;
+ this.platformList = platform;
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/models/dynamicInput.ts b/vid-webpack-master/src/app/shared/models/dynamicInput.ts
new file mode 100644
index 000000000..a08cdfc77
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/dynamicInput.ts
@@ -0,0 +1,123 @@
+export class DynamicInput<T>{
+
+ id: string;
+ name: string;
+ type: string;
+ description: string;
+ value: T;
+ prompt: any;
+ maxLength: number;
+ minLength: number;
+ isVisible: boolean;
+ isRequired: boolean;
+ isEnabled: boolean;
+ isReadOnly: boolean;
+
+
+ constructor(options: {
+ id?: string,
+ name?: string,
+ type: string,
+ description?: string,
+ value?: T,
+ prompt?: any,
+ maxLength?: number,
+ minLength?: number,
+ isVisible?: boolean,
+ isRequired?: boolean,
+ isEnabled?: boolean,
+ isReadOnly?: boolean,
+ }) {
+ this.id = options.id;
+ this.name = options.name || '';
+ this.type = options.type;
+ this.description = options.description || '';
+ this.value = options.value;
+ this.prompt = options.prompt;
+ this.maxLength = options.maxLength;
+ this.minLength = options.minLength;
+ this.isVisible = options.isVisible == false? options.isVisible: true;
+ this.isEnabled = options.isEnabled == false? options.isEnabled: true;
+ this.isRequired = options.isRequired == null? false: options.isRequired;
+ this.isReadOnly = options.isReadOnly == null? false: options.isReadOnly;
+ }
+}
+
+export class DynamicNumber extends DynamicInput<number> {
+
+ max: number;
+ min: number;
+
+ constructor(options: {
+ id?: string,
+ name?: string,
+ type: string,
+ description?: string,
+ value?: number,
+ prompt?: any,
+ maxLength?: number,
+ minLength?: number,
+ isVisible?: boolean,
+ isRequired?: boolean,
+ isEnabled?: boolean,
+ isReadOnly?: boolean,
+ max?: number,
+ min?: number
+ }){
+ super(options);
+ this.max = options.max;
+ this.min = options.min;
+ }
+
+}
+
+export class DynamicSelect extends DynamicInput<any> {
+ optionList: any[];
+
+ constructor(options: {
+ id?: string,
+ name?: string,
+ type: string,
+ description?: string,
+ value?: any,
+ prompt?: any,
+ maxLength?: number,
+ minLength?: number,
+ isVisible?: boolean,
+ isRequired?: boolean,
+ isEnabled?: boolean,
+ isReadOnly?: boolean,
+ optionList?: any[]
+ }) {
+ super(options);
+ this.optionList = options.optionList || [];
+ }
+}
+
+export class DynamicMultiSelect extends DynamicSelect {
+ selectedItems: any[];
+ settings: any;
+
+ constructor(options: {
+ id?: string,
+ name?: string,
+ type: string,
+ description?: string,
+ value?: any,
+ prompt?: any,
+ maxLength?: number,
+ minLength?: number,
+ isVisible?: boolean,
+ isRequired?: boolean,
+ isEnabled?: boolean,
+ isReadOnly?: boolean,
+ settings?: any,
+ optionList?: any[],
+ selectedItems?: any[]
+ }) {
+ super(options);
+ this.settings = options.settings || {};
+ this.selectedItems = options.selectedItems || [];
+ }
+}
+
diff --git a/vid-webpack-master/src/app/shared/models/externalComponentStatus.ts b/vid-webpack-master/src/app/shared/models/externalComponentStatus.ts
new file mode 100644
index 000000000..21ef61a8a
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/externalComponentStatus.ts
@@ -0,0 +1,11 @@
+export class ExternalComponentStatus {
+ component: string;
+ available: boolean;
+ metadata: any;
+
+ constructor(component: string, available: boolean, metadata: any) {
+ this.component = component;
+ this.available = available;
+ this.metadata = metadata;
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/models/inputTypes.ts b/vid-webpack-master/src/app/shared/models/inputTypes.ts
new file mode 100644
index 000000000..1f7222f52
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/inputTypes.ts
@@ -0,0 +1,12 @@
+export enum InputType {
+ LCP_REGION = "LCP_REGION",
+ TENANT = "TENANT",
+ LOB = "LOB",
+ PLATFORM = "PLATFORM",
+ ROLLBACK = "ROLLBACK",
+ PRODUCT_FAMILY = "PRODUCT_FAMILY",
+ VG = "VG"
+
+}
+
+
diff --git a/vid-webpack-master/src/app/shared/models/lcpRegion.ts b/vid-webpack-master/src/app/shared/models/lcpRegion.ts
new file mode 100644
index 000000000..e39321d58
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/lcpRegion.ts
@@ -0,0 +1,11 @@
+export class LcpRegion {
+ id: string;
+ name: string;
+ isPermitted: boolean;
+
+ constructor(serviceJson){
+ this.id = serviceJson["cloudRegionID"];
+ this.name = serviceJson["cloudRegionID"];
+ this.isPermitted = serviceJson["is-permitted"];
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/models/lcpRegionTenants.ts b/vid-webpack-master/src/app/shared/models/lcpRegionTenants.ts
new file mode 100644
index 000000000..d215546aa
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/lcpRegionTenants.ts
@@ -0,0 +1,13 @@
+export class LcpRegionTenants {
+ id: string;
+ tenantId: string;
+ tenantName: string;
+ isPermitted: boolean;
+
+ constructor(serviceJson){
+ this.id = serviceJson["cloudRegionID"];
+ this.tenantId = serviceJson["tenantID"];
+ this.tenantName = serviceJson["tenantName"];
+ this.isPermitted = serviceJson["is-permitted"];
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/models/lcpRegionsAndTenants.ts b/vid-webpack-master/src/app/shared/models/lcpRegionsAndTenants.ts
new file mode 100644
index 000000000..79f6e07d4
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/lcpRegionsAndTenants.ts
@@ -0,0 +1,12 @@
+import {LcpRegion} from "./lcpRegion";
+import {Tenant} from "./tenant";
+
+export class LcpRegionsAndTenants {
+ lcpRegionList: LcpRegion[];
+ lcpRegionsTenantsMap: { [lcpRegion: string] : Tenant[]; };
+
+ constructor(lcpRegionList: LcpRegion[] = [], lcpRegionsTenantsMap: any = {}) {
+ this.lcpRegionList = lcpRegionList;
+ this.lcpRegionsTenantsMap = lcpRegionsTenantsMap;
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/models/modelInfo.ts b/vid-webpack-master/src/app/shared/models/modelInfo.ts
new file mode 100644
index 000000000..091c02ef1
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/modelInfo.ts
@@ -0,0 +1,21 @@
+
+export class ModelInfo {
+ modelInvariantId: string;
+ modelVersionId: string;
+ modelName: string;
+ modelVersion: string;
+ modelCustomizationId: string;
+ modelCustomizationName: string;
+
+
+
+ constructor(instanceModel) {
+ this.modelInvariantId = instanceModel.invariantUuid;
+ this.modelVersionId = instanceModel.uuid;
+ this.modelName = instanceModel.name;
+ this.modelVersion = instanceModel.version;
+ this.modelCustomizationId = instanceModel.customizationUuid;
+ this.modelCustomizationName = instanceModel.modelCustomizationName;
+ }
+}
+
diff --git a/vid-webpack-master/src/app/shared/models/nodeModel.ts b/vid-webpack-master/src/app/shared/models/nodeModel.ts
new file mode 100644
index 000000000..4b22b8d91
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/nodeModel.ts
@@ -0,0 +1,29 @@
+export interface NodeModelResponseInterface {
+ name: string;
+ version: string;
+ description: string;
+ category: string;
+ uuid: string;
+ invariantUuid: string;
+}
+
+export class NodeModel {
+ name: string;
+ version: string;
+ description: string;
+ category: string;
+ uuid: string;
+ invariantUuid: string;
+
+ constructor(serviceJson?: NodeModelResponseInterface) {
+ if (serviceJson) {
+ this.name = serviceJson.name;
+ this.version = serviceJson.version;
+ this.description = serviceJson.description;
+ this.category = serviceJson.category;
+ this.uuid = serviceJson.uuid;
+ this.invariantUuid = serviceJson.invariantUuid;
+ }
+ }
+
+}
diff --git a/vid-webpack-master/src/app/shared/models/owningEntity.ts b/vid-webpack-master/src/app/shared/models/owningEntity.ts
new file mode 100644
index 000000000..f06b24ff0
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/owningEntity.ts
@@ -0,0 +1,14 @@
+interface OwningEntityResponse {
+ id: string,
+ name: string
+}
+
+export class OwningEntity {
+ id: string;
+ name: string;
+
+ constructor(serviceJson: OwningEntityResponse){
+ this.id = serviceJson.id;
+ this.name = serviceJson.name;
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/models/productFamily.ts b/vid-webpack-master/src/app/shared/models/productFamily.ts
new file mode 100644
index 000000000..3c55ac004
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/productFamily.ts
@@ -0,0 +1,13 @@
+import {ServiceResponseInterface} from "../../services/aaiService/responseInterfaces/getServicesResponseInterface";
+
+export class ProductFamily {
+ id: string;
+ name: string;
+ isPermitted: boolean;
+
+ constructor(serviceResponse: ServiceResponseInterface){
+ this.id = serviceResponse['service-id'];
+ this.name = serviceResponse["service-description"];
+ this.isPermitted = serviceResponse["is-permitted"];
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/models/project.ts b/vid-webpack-master/src/app/shared/models/project.ts
new file mode 100644
index 000000000..db8929e38
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/project.ts
@@ -0,0 +1,14 @@
+interface ProjectResponseInterface {
+ id: string,
+ name: string
+}
+
+export class Project {
+ id: string;
+ name: string;
+
+ constructor(projectResponse: ProjectResponseInterface){
+ this.id = projectResponse.id;
+ this.name = projectResponse.name;
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/models/selectOption.ts b/vid-webpack-master/src/app/shared/models/selectOption.ts
new file mode 100644
index 000000000..c12c1a823
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/selectOption.ts
@@ -0,0 +1,17 @@
+export interface SelectOptionInterface {
+ id: string,
+ name: string
+ isPermitted?: boolean
+}
+
+export class SelectOption {
+ id: string;
+ name: string;
+ isPermitted?: boolean;
+
+ constructor(option: SelectOptionInterface){
+ this.id = option.id;
+ this.name = option.name;
+ this.isPermitted = option.isPermitted;
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/models/serviceInstance.ts b/vid-webpack-master/src/app/shared/models/serviceInstance.ts
new file mode 100644
index 000000000..a952430b0
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/serviceInstance.ts
@@ -0,0 +1,28 @@
+import {VnfInstance} from "./vnfInstance";
+
+export class ServiceInstance {
+ instanceName: string;
+ isUserProvidedNaming: boolean;
+ globalSubscriberId: string;
+ productFamilyId: string;
+ subscriptionServiceType: string;
+ lcpCloudRegionId: string;
+ tenantId: string;
+ tenantName: string;
+ aicZoneId: string;
+ aicZoneName: string;
+ projectName: string;
+ owningEntityId: string;
+ owningEntityName: string;
+ pause: boolean;
+ bulkSize: number;
+ vnfs: { [vnf_module_model_name: string] : VnfInstance; };
+ instanceParams: { [key: string] : string; };
+ rollbackOnFailure : boolean;
+ subscriberName : string;
+
+ constructor() {
+ this.vnfs = {};
+ this.instanceParams = {};
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/models/serviceModel.ts b/vid-webpack-master/src/app/shared/models/serviceModel.ts
new file mode 100644
index 000000000..18d8582e8
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/serviceModel.ts
@@ -0,0 +1,44 @@
+import {NodeModel, NodeModelResponseInterface} from "./nodeModel";
+import * as _ from "lodash";
+
+
+export interface ServiceModelResponseInterface extends NodeModelResponseInterface{
+
+ serviceType: string;
+ serviceRole: string;
+ serviceEcompNaming: boolean;
+}
+
+export class ServiceModel extends NodeModel{
+
+ serviceType: string;
+ serviceRole: string;
+ servicesQty: number;
+ isUserProvidedNaming: boolean;
+ isMultiStepDesign: boolean;
+
+ constructor(serviceModelJson?: any){
+ super(serviceModelJson.service);
+ if (serviceModelJson) {
+ const service: ServiceModelResponseInterface = serviceModelJson.service;
+ this.serviceType = service.serviceType;
+ this.serviceRole = service.serviceRole;
+ this.isUserProvidedNaming = this.getIsUserProvidedName(service);
+ this.isMultiStepDesign = this.getIsMultiStepDesign(serviceModelJson);
+ }
+ }
+
+ private getIsUserProvidedName(serviceJson): boolean {
+ return serviceJson.serviceEcompNaming !== undefined && serviceJson.serviceEcompNaming === "false";
+ };
+
+ private getIsMultiStepDesign(serviceModel): boolean {
+ for (let key in serviceModel.vnfs) {
+ const vnf = serviceModel.vnfs[key];
+ if (vnf.properties.multi_stage_design === "true") {
+ return true
+ }
+ }
+ return false;
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/models/serviceNodeTypeToModelKeyMapper.ts b/vid-webpack-master/src/app/shared/models/serviceNodeTypeToModelKeyMapper.ts
new file mode 100644
index 000000000..1134bbb89
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/serviceNodeTypeToModelKeyMapper.ts
@@ -0,0 +1,8 @@
+export enum ServiceNodeTypeToModelKeyMapper {
+ VF = "vnfs",
+ VFmodule="vfModules",
+ Network = "networks",
+ Configuration = "configurations"
+}
+
+
diff --git a/vid-webpack-master/src/app/shared/models/serviceType.ts b/vid-webpack-master/src/app/shared/models/serviceType.ts
new file mode 100644
index 000000000..67aacdc07
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/serviceType.ts
@@ -0,0 +1,17 @@
+export interface SubscriptionResponseInterface {
+ 'service-type': string
+ 'is-permitted': boolean
+}
+
+export class ServiceType {
+ id: string;
+ name: string;
+ isPermitted: boolean;
+
+
+ constructor(id: string, subscription: SubscriptionResponseInterface){
+ this.id = id;
+ this.name = subscription['service-type'];
+ this.isPermitted = subscription['is-permitted'];
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/models/subscriber.ts b/vid-webpack-master/src/app/shared/models/subscriber.ts
new file mode 100644
index 000000000..55fc83792
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/subscriber.ts
@@ -0,0 +1,11 @@
+export class Subscriber {
+ id: string;
+ name: string;
+ isPermitted: boolean;
+
+ constructor(subscriberResponse){
+ this.id = subscriberResponse['global-customer-id'];
+ this.name = subscriberResponse['subscriber-name'];
+ this.isPermitted = subscriberResponse['is-permitted'];
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/models/tenant.ts b/vid-webpack-master/src/app/shared/models/tenant.ts
new file mode 100644
index 000000000..234f1dbff
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/tenant.ts
@@ -0,0 +1,11 @@
+export class Tenant {
+ id: string;
+ name: string;
+ isPermitted: boolean;
+
+ constructor(serviceJson){
+ this.id = serviceJson["tenantID"];
+ this.name = serviceJson["tenantName"];
+ this.isPermitted = serviceJson["is-permitted"];
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/models/vfModule.ts b/vid-webpack-master/src/app/shared/models/vfModule.ts
new file mode 100644
index 000000000..21f43ed17
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/vfModule.ts
@@ -0,0 +1,39 @@
+import {NodeModel, NodeModelResponseInterface} from "./nodeModel";
+
+
+export interface properties{
+ initialCount: number;
+ maxCountInstances: number;
+ minCountInstances: number;
+}
+
+export interface VFModuleResponseInterface extends NodeModelResponseInterface {
+ customizationUuid: string;
+ modelCustomizationName: string;
+ properties: properties
+}
+
+export class VfModule extends NodeModel {
+
+ min:number;
+ max:number;
+ vgName:string;
+ rollbackOnFailure:boolean;
+ initial:number;
+ customizationUuid: string;
+ modelCustomizationName: string;
+
+ constructor(vf?: VFModuleResponseInterface) {
+ super(vf);
+ if(vf){
+ this.customizationUuid = vf.customizationUuid;
+ this.modelCustomizationName = vf.modelCustomizationName;
+ }
+ if (vf && vf.properties) {
+ this.min = vf.properties.minCountInstances;
+ this.max = vf.properties.maxCountInstances;
+ this.initial = vf.properties.initialCount;
+ this.rollbackOnFailure = true
+ }
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/models/vfModuleInstance.ts b/vid-webpack-master/src/app/shared/models/vfModuleInstance.ts
new file mode 100644
index 000000000..c6db00025
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/vfModuleInstance.ts
@@ -0,0 +1,5 @@
+export class VfModuleInstance {
+ instanceName: string;
+ volumeGroupName: string;
+ instanceParams: { [key: string] : string; };
+}
diff --git a/vid-webpack-master/src/app/shared/models/vfModuleTreeNode.ts b/vid-webpack-master/src/app/shared/models/vfModuleTreeNode.ts
new file mode 100644
index 000000000..d4cc7e9c7
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/vfModuleTreeNode.ts
@@ -0,0 +1,17 @@
+import {VfModule} from "./vfModule";
+import {VfModuleInstance} from "./vfModuleInstance";
+import {ServiceNodeTypes} from "./ServiceNodeTypes";
+
+export class VfModuleTreeNode {
+ modelId: string;
+ name: string;
+ modelName: string;
+ type: string;
+
+ constructor(vfModuleInstance: VfModuleInstance, vfModuleModel: VfModule, vfModuleModelName: string){
+ this.name = vfModuleInstance.instanceName || vfModuleInstance.volumeGroupName || '<Automatically Assigned>';
+ this.modelId = vfModuleModel.uuid;
+ this.modelName = vfModuleModelName;
+ this.type = ServiceNodeTypes.VFmodule;
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/models/vfModulesMap.ts b/vid-webpack-master/src/app/shared/models/vfModulesMap.ts
new file mode 100644
index 000000000..95396fd55
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/vfModulesMap.ts
@@ -0,0 +1,5 @@
+import {VfModuleInstance} from "./vfModuleInstance";
+
+export class VfModuleMap {
+ [id: string] : VfModuleInstance;
+}
diff --git a/vid-webpack-master/src/app/shared/models/vfcInstanceGroup.ts b/vid-webpack-master/src/app/shared/models/vfcInstanceGroup.ts
new file mode 100644
index 000000000..64354b01e
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/vfcInstanceGroup.ts
@@ -0,0 +1,14 @@
+import {VfcInstanceGroupProperties} from "./vfcInstanceGroupProperties";
+
+export class VfcInstanceGroup {
+ name: string;
+ version: string;
+ uuid: string;
+ invariantUuid: string;
+ vfcInstanceGroupProperties: VfcInstanceGroupProperties;
+
+
+}
+
+
+
diff --git a/vid-webpack-master/src/app/shared/models/vfcInstanceGroupMap.ts b/vid-webpack-master/src/app/shared/models/vfcInstanceGroupMap.ts
new file mode 100644
index 000000000..7ee3888c1
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/vfcInstanceGroupMap.ts
@@ -0,0 +1,5 @@
+import {VfcInstanceGroup} from "./vfcInstanceGroup";
+
+export class VfcInstanceGroupMap {
+ [id: string] : VfcInstanceGroup;
+}
diff --git a/vid-webpack-master/src/app/shared/models/vfcInstanceGroupProperties.ts b/vid-webpack-master/src/app/shared/models/vfcInstanceGroupProperties.ts
new file mode 100644
index 000000000..1a7bf718a
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/vfcInstanceGroupProperties.ts
@@ -0,0 +1,7 @@
+export class VfcInstanceGroupProperties {
+ networkCollectionFunction: string;
+ subinterfaceRole: string;
+ vfcInstanceGroupFunction: string;
+ vfcParentPortRole: string;
+
+}
diff --git a/vid-webpack-master/src/app/shared/models/vnfInstance.ts b/vid-webpack-master/src/app/shared/models/vnfInstance.ts
new file mode 100644
index 000000000..7f41e483a
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/vnfInstance.ts
@@ -0,0 +1,19 @@
+import {VfModuleMap} from "./vfModulesMap";
+
+export class VnfInstance {
+ instanceName: string;
+ isUserProvidedNaming: boolean;
+ productFamilyId: string;
+ lcpCloudRegionId: string;
+ legacyRegion: string;
+ tenantId: string;
+ platformName: string;
+ lineOfBusiness: string;
+ rollbackOnFailure: string;
+ vfModules: { [vf_module_model_name: string] : VfModuleMap; };
+
+ constructor() {
+ this.rollbackOnFailure = 'true';
+ this.vfModules = {};
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/models/vnfModel.ts b/vid-webpack-master/src/app/shared/models/vnfModel.ts
new file mode 100644
index 000000000..e1302f1d0
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/vnfModel.ts
@@ -0,0 +1,52 @@
+import {NodeModel, NodeModelResponseInterface} from "./nodeModel";
+import {VfcInstanceGroupMap} from "./vfcInstanceGroupMap";
+
+
+export interface VnfProperties {
+ ecomp_generated_naming: string
+}
+
+export interface VNFModelResponseInterface extends NodeModelResponseInterface{
+
+ serviceType: string;
+ serviceRole: string;
+ subCategory: string;
+ customizationUuid: string;
+ serviceEcompNaming: boolean;
+ type: string;
+ modelCustomizationName: string;
+ properties: VnfProperties;
+ vfcInstanceGroups: VfcInstanceGroupMap;
+}
+
+export class VNFModel extends NodeModel{
+
+ serviceType: string;
+ serviceRole: string;
+ subCategory: string;
+ customizationUuid: string;
+ isUserProvidedNaming: boolean;
+ type: string;
+ modelCustomizationName: string;
+ vfcInstanceGroups: VfcInstanceGroupMap;
+
+ constructor(vnfJson?: VNFModelResponseInterface){
+ super(vnfJson);
+ if (vnfJson) {
+ this.serviceType = vnfJson.serviceType;
+ this.serviceRole = vnfJson.serviceRole;
+ this.subCategory = vnfJson.subCategory;
+ this.customizationUuid = vnfJson.customizationUuid;
+ this.isUserProvidedNaming = this.getIsUserProvidedName(vnfJson);
+ this.type = vnfJson.type;
+ this.modelCustomizationName = vnfJson.modelCustomizationName;
+ this.vfcInstanceGroups = vnfJson.vfcInstanceGroups;
+
+ }
+ }
+
+ private getIsUserProvidedName(vnfJson) {
+ const ecompGeneratedNaming = vnfJson.properties.ecomp_generated_naming;
+ return ecompGeneratedNaming !== undefined && ecompGeneratedNaming === "false";
+ };
+}
diff --git a/vid-webpack-master/src/app/shared/models/vnfTreeNode.ts b/vid-webpack-master/src/app/shared/models/vnfTreeNode.ts
new file mode 100644
index 000000000..316bf3e8b
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/models/vnfTreeNode.ts
@@ -0,0 +1,18 @@
+import {VNFModel} from "./vnfModel";
+import {VnfInstance} from "./vnfInstance";
+import {VfModuleTreeNode} from "./vfModuleTreeNode";
+
+export class VnfTreeNode {
+ modelId: string;
+ name: string;
+ modelName: string;
+ type: string;
+ children: VfModuleTreeNode[];
+
+ constructor(instance: VnfInstance, vnfModel: VNFModel){
+ this.name = instance.instanceName || vnfModel['properties'].ecomp_generated_naming == 'false' ? vnfModel.modelCustomizationName : '<Automatically Assigned>';
+ this.modelId = vnfModel.uuid;
+ this.modelName = vnfModel.modelCustomizationName;
+ this.type = vnfModel.type;
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/pipes/capitalize/capitalize-and-format.pipe.spec.ts b/vid-webpack-master/src/app/shared/pipes/capitalize/capitalize-and-format.pipe.spec.ts
new file mode 100644
index 000000000..84d2ff4b6
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/pipes/capitalize/capitalize-and-format.pipe.spec.ts
@@ -0,0 +1,25 @@
+
+import {CapitalizeAndFormatPipe} from "./capitalize-and-format.pipe";
+
+describe('Capitalize And Format Pipe', () => {
+ let capitalizeAndFormatPipe: CapitalizeAndFormatPipe;
+
+ beforeEach(() => {
+ capitalizeAndFormatPipe = new CapitalizeAndFormatPipe();
+ });
+
+ it('Capitalize And Format Pipe should be defined', () => {
+ expect(capitalizeAndFormatPipe).toBeDefined();
+ });
+
+ it('Capitalize And Format Pipe : (UPPERCASE)', ()=> {
+ let result: string = capitalizeAndFormatPipe.transform('PENDING');
+ expect(result).toEqual('Pending');
+ });
+
+ it('Capitalize And Format Pipe (UPPERCASE) and Underscore should replace by -', ()=> {
+ let result: string = capitalizeAndFormatPipe.transform('IN_PROGRESS');
+ expect(result).toEqual('In-progress');
+ });
+
+});
diff --git a/vid-webpack-master/src/app/shared/pipes/capitalize/capitalize-and-format.pipe.ts b/vid-webpack-master/src/app/shared/pipes/capitalize/capitalize-and-format.pipe.ts
new file mode 100644
index 000000000..e3ec9ae9a
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/pipes/capitalize/capitalize-and-format.pipe.ts
@@ -0,0 +1,12 @@
+import {PipeTransform, Pipe} from '@angular/core';
+
+@Pipe({ name: 'capitalizeAndFormat' })
+export class CapitalizeAndFormatPipe implements PipeTransform {
+ transform(text: string): string {
+ if (text) {
+ text = text.toLowerCase().replace('_', '-');
+ return text.charAt(0).toUpperCase() + text.slice(1);
+ }
+ return text;
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/pipes/data-filter.pipe.ts b/vid-webpack-master/src/app/shared/pipes/data-filter.pipe.ts
new file mode 100644
index 000000000..1ff836762
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/pipes/data-filter.pipe.ts
@@ -0,0 +1,29 @@
+/**
+ * Created by cp2122 on 1/4/2018.
+ */
+import { Pipe, PipeTransform } from '@angular/core';
+
+@Pipe({
+ name: 'dataFilter'
+})
+export class DataFilterPipe implements PipeTransform {
+ keys = [];
+ transform(items: any, args: string): any {
+ if (items != null && items.length > 0) {
+ let ans = [];
+
+ if (this.keys.length === 0) {
+ this.keys = Object.keys(items[0]);
+ }
+ for (let i of items) {
+ for (let k of this.keys) {
+ if (i[k] !== null && i[k].toString().match('^.*' + args + '.*$')) {
+ ans.push(i);
+ break;
+ }
+ }
+ }
+ return ans;
+ }
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/pipes/dynamicInputLabel/dynamic-input-label.pipe.spec.ts b/vid-webpack-master/src/app/shared/pipes/dynamicInputLabel/dynamic-input-label.pipe.spec.ts
new file mode 100644
index 000000000..22b619290
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/pipes/dynamicInputLabel/dynamic-input-label.pipe.spec.ts
@@ -0,0 +1,43 @@
+import { DynamicInputLabelPipe } from './dynamic-input-label.pipe';
+
+describe('Dynamic input label Pipe', () => {
+ let dynamicInputLabelPipe: DynamicInputLabelPipe;
+
+ beforeEach(() => {
+ dynamicInputLabelPipe = new DynamicInputLabelPipe();
+ });
+
+ it('Dynamic input label Pipe should be defined', () => {
+ expect(dynamicInputLabelPipe).toBeDefined();
+ });
+
+ it('Dynamic input label Pipe : Empty string should return empty string', ()=> {
+ let result: string = dynamicInputLabelPipe.transform('');
+ expect(result).toEqual(':*');
+ });
+
+ it('Dynamic input label Pipe: vnf should be VNF (UPPERCASE)', ()=> {
+ let result: string = dynamicInputLabelPipe.transform('vnf');
+ expect(result).toEqual('VNF:*');
+ });
+
+ it('Dynamic input label Pipe : nf should be NF (UPPERCASE)\'', ()=> {
+ let result: string = dynamicInputLabelPipe.transform('nf');
+ expect(result).toEqual('NF:*');
+ });
+
+ it('Dynamic input label Pipe : Underscore should replace by empty character', ()=> {
+ let result: string = dynamicInputLabelPipe.transform('nf_Test');
+ expect(result).toEqual('NF test:*');
+ });
+
+ it('Dynamic input label Pipe : Complex string', ()=> {
+ let result: string = dynamicInputLabelPipe.transform('nf_Test_vnf_nf');
+ expect(result).toEqual('NF test VNF NF:*');
+ });
+
+ it('Dynamic input label Pipe : First letter should be uppercase', ()=> {
+ let result: string = dynamicInputLabelPipe.transform('nfr');
+ expect(result).toEqual('Nfr:*');
+ });
+});
diff --git a/vid-webpack-master/src/app/shared/pipes/dynamicInputLabel/dynamic-input-label.pipe.ts b/vid-webpack-master/src/app/shared/pipes/dynamicInputLabel/dynamic-input-label.pipe.ts
new file mode 100644
index 000000000..bec87b46d
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/pipes/dynamicInputLabel/dynamic-input-label.pipe.ts
@@ -0,0 +1,12 @@
+import {PipeTransform, Pipe} from '@angular/core';
+
+@Pipe({ name: 'dynamicInputLabel' })
+export class DynamicInputLabelPipe implements PipeTransform {
+ transform(text: string): string {
+ let split_label = text.toLowerCase().replace(/_/g,' ');
+ let uppercase_vnf = split_label.replace(/\bvnf\b/ig, 'VNF');
+ let uppercase_nf = uppercase_vnf.replace(/\bnf\b/ig, 'NF');
+ let capitalize_sentence = uppercase_nf.charAt(0).toUpperCase() + uppercase_nf.slice(1);
+ return capitalize_sentence + ':*';
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/pipes/highlight-filter.pipe.ts b/vid-webpack-master/src/app/shared/pipes/highlight-filter.pipe.ts
new file mode 100644
index 000000000..93aecbf69
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/pipes/highlight-filter.pipe.ts
@@ -0,0 +1,10 @@
+import {PipeTransform, Pipe} from '@angular/core';
+
+@Pipe({ name: 'highlight' })
+export class HighlightPipe implements PipeTransform {
+ transform(text: string, search: string): string {
+ let pattern = search.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&');
+ let regex = new RegExp(pattern, 'gi');
+ return search ? text.replace(regex, (match) => `<span class="highlight">${match}</span>`) : text;
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/pipes/serviceInfo/serviceInfo.pipe.spec.ts b/vid-webpack-master/src/app/shared/pipes/serviceInfo/serviceInfo.pipe.spec.ts
new file mode 100644
index 000000000..984e3378c
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/pipes/serviceInfo/serviceInfo.pipe.spec.ts
@@ -0,0 +1,58 @@
+import {ServiceInfoPipe} from "./serviceInfo.pipe";
+
+
+describe('Service info Pipe', () => {
+ let pipe: ServiceInfoPipe;
+
+ beforeEach(() => {
+ pipe = new ServiceInfoPipe();
+ });
+
+ it('Service info Pipe should return model name', () => {
+ let store = {
+ getState : function() {
+ return {
+ service: {
+ serviceHierarchy : generateserviceHierarchy()
+ }
+ }
+ }
+ };
+ let result : string = pipe.transform(null, store , '6e59c5de-f052-46fa-aa7e-2fca9d674c44', 'name');
+ expect(result).toEqual('ComplexService')
+ });
+
+
+
+ it('Service info Pipe should return null if field name not exist', () => {
+ let store = {
+ getState : function() {
+ return {
+ service: {
+ serviceHierarchy : generateserviceHierarchy()
+ }
+ }
+ }
+ };
+ let result : string = pipe.transform(null, store , '6e59c5de-f052-46fa-aa7e-2fca9d674c44', 'notExist');
+ expect(result).toBeNull();
+ });
+
+ it('Service info Pipe should return null if model not exist', () => {
+ let store = {
+ getState : function() {
+ return {
+ service: {
+ serviceHierarchy : generateserviceHierarchy()
+ }
+ }
+ }
+ };
+ let result : string = pipe.transform(null, store , 'modelNotExist', 'name');
+ expect(result).toBeNull();
+ });
+
+ function generateserviceHierarchy(){
+ return JSON.parse('{"6e59c5de-f052-46fa-aa7e-2fca9d674c44":{"service":{"uuid":"6e59c5de-f052-46fa-aa7e-2fca9d674c44","invariantUuid":"e49fbd11-e60c-4a8e-b4bf-30fbe8f4fcc0","name":"ComplexService","version":"1.0","toscaModelURL":null,"category":"Mobility","serviceType":"","serviceRole":"","description":"ComplexService","serviceEcompNaming":"true","instantiationType":"Macro","inputs":{}},"vnfs":{"VF_vMee 0":{"uuid":"d6557200-ecf2-4641-8094-5393ae3aae60","invariantUuid":"4160458e-f648-4b30-a176-43881ffffe9e","description":"VSP_vMee","name":"VF_vMee","version":"2.0","customizationUuid":"91415b44-753d-494c-926a-456a9172bbb9","inputs":{},"commands":{},"properties":{"gpb2_Internal2_mac":"00:80:37:0E:02:22","sctp-b-ipv6-egress_src_start_port":"0","sctp-a-ipv6-egress_rule_application":"any","Internal2_allow_transit":"true","sctp-b-IPv6_ethertype":"IPv6","sctp-a-egress_rule_application":"any","sctp-b-ingress_action":"pass","sctp-b-ingress_rule_protocol":"icmp","ncb2_Internal1_mac":"00:80:37:0E:0F:12","sctp-b-ipv6-ingress-src_start_port":"0.0","ncb1_Internal2_mac":"00:80:37:0E:09:12","fsb_volume_size_0":"320.0","sctp-b-egress_src_addresses":"local","sctp-a-ipv6-ingress_ethertype":"IPv4","sctp-a-ipv6-ingress-dst_start_port":"0","sctp-b-ipv6-ingress_rule_application":"any","domain_name":"default-domain","sctp-a-ingress_rule_protocol":"icmp","sctp-b-egress-src_start_port":"0.0","sctp-a-egress_src_addresses":"local","sctp-b-display_name":"epc-sctp-b-ipv4v6-sec-group","sctp-a-egress-src_start_port":"0.0","sctp-a-ingress_ethertype":"IPv4","sctp-b-ipv6-ingress-dst_end_port":"65535","sctp-b-dst_subnet_prefix_v6":"::","nf_naming":"{ecomp_generated_naming=true}","sctp-a-ipv6-ingress_src_subnet_prefix":"0.0.0.0","sctp-b-egress-dst_start_port":"0.0","ncb_flavor_name":"nv.c20r64d1","gpb1_Internal1_mac":"00:80:37:0E:01:22","sctp-b-egress_dst_subnet_prefix_len":"0.0","Internal2_net_cidr":"169.255.0.0","sctp-a-ingress-dst_start_port":"0.0","sctp-a-egress-dst_start_port":"0.0","fsb1_Internal2_mac":"00:80:37:0E:0B:12","sctp-a-egress_ethertype":"IPv4","vlc_st_service_mode":"in-network-nat","sctp-a-ipv6-egress_ethertype":"IPv4","sctp-a-egress-src_end_port":"65535.0","sctp-b-ipv6-egress_rule_application":"any","sctp-b-egress_action":"pass","sctp-a-ingress-src_subnet_prefix_len":"0.0","sctp-b-ipv6-ingress-src_end_port":"65535.0","sctp-b-name":"epc-sctp-b-ipv4v6-sec-group","fsb2_Internal1_mac":"00:80:37:0E:0D:12","sctp-a-ipv6-ingress-src_start_port":"0.0","sctp-b-ipv6-egress_ethertype":"IPv4","Internal1_net_cidr":"169.253.0.0","sctp-a-egress_dst_subnet_prefix":"0.0.0.0","fsb_flavor_name":"nv.c20r64d1","sctp_rule_protocol":"132","sctp-b-ipv6-ingress_src_subnet_prefix_len":"0","sctp-a-ipv6-ingress_rule_application":"any","ecomp_generated_naming":"true","sctp-a-IPv6_ethertype":"IPv6","vlc2_Internal1_mac":"00:80:37:0E:02:12","vlc_st_virtualization_type":"virtual-machine","sctp-b-ingress-dst_start_port":"0.0","sctp-b-ingress-dst_end_port":"65535.0","sctp-a-ipv6-ingress-src_end_port":"65535.0","sctp-a-display_name":"epc-sctp-a-ipv4v6-sec-group","sctp-b-ingress_rule_application":"any","int2_sec_group_name":"int2-sec-group","vlc_flavor_name":"nd.c16r64d1","sctp-b-ipv6-egress_src_addresses":"local","vlc_st_interface_type_int1":"other1","sctp-b-egress-src_end_port":"65535.0","sctp-a-ipv6-egress-dst_start_port":"0","vlc_st_interface_type_int2":"other2","sctp-a-ipv6-egress_rule_protocol":"any","Internal2_shared":"false","sctp-a-ipv6-egress_dst_subnet_prefix_len":"0","Internal2_rpf":"disable","vlc1_Internal1_mac":"00:80:37:0E:01:12","sctp-b-ipv6-egress_src_end_port":"65535","sctp-a-ipv6-egress_src_addresses":"local","sctp-a-ingress-dst_end_port":"65535.0","sctp-a-ipv6-egress_src_end_port":"65535","Internal1_forwarding_mode":"l2","Internal2_dhcp":"false","sctp-a-dst_subnet_prefix_v6":"::","pxe_image_name":"MME_PXE-Boot_16ACP04_GA.qcow2","vlc_st_interface_type_gtp":"other0","ncb1_Internal1_mac":"00:80:37:0E:09:12","sctp-b-src_subnet_prefix_v6":"::","sctp-a-egress_dst_subnet_prefix_len":"0.0","int1_sec_group_name":"int1-sec-group","Internal1_dhcp":"false","sctp-a-ipv6-egress_dst_end_port":"65535","Internal2_forwarding_mode":"l2","fsb2_Internal2_mac":"00:80:37:0E:0D:12","sctp-b-egress_dst_subnet_prefix":"0.0.0.0","Internal1_net_cidr_len":"17","gpb2_Internal1_mac":"00:80:37:0E:02:22","sctp-b-ingress-src_subnet_prefix_len":"0.0","sctp-a-ingress_dst_addresses":"local","sctp-a-egress_action":"pass","fsb_volume_type_0":"SF-Default-SSD","ncb2_Internal2_mac":"00:80:37:0E:0F:12","vlc_st_interface_type_sctp_a":"left","vlc_st_interface_type_sctp_b":"right","sctp-a-src_subnet_prefix_v6":"::","vlc_st_version":"2","sctp-b-egress_ethertype":"IPv4","sctp-a-ingress_rule_application":"any","gpb1_Internal2_mac":"00:80:37:0E:01:22","instance_ip_family_v6":"v6","sctp-a-ipv6-egress_src_start_port":"0","sctp-b-ingress-src_start_port":"0.0","sctp-b-ingress_dst_addresses":"local","fsb1_Internal1_mac":"00:80:37:0E:0B:12","vlc_st_interface_type_oam":"management","multi_stage_design":"false","oam_sec_group_name":"oam-sec-group","Internal2_net_gateway":"169.255.0.3","sctp-a-ipv6-ingress-dst_end_port":"65535","sctp-b-ipv6-egress-dst_start_port":"0","Internal1_net_gateway":"169.253.0.3","sctp-b-ipv6-egress_rule_protocol":"any","gtp_sec_group_name":"gtp-sec-group","sctp-a-ipv6-egress_dst_subnet_prefix":"0.0.0.0","sctp-b-ipv6-egress_dst_subnet_prefix_len":"0","sctp-a-ipv6-ingress_dst_addresses":"local","sctp-a-egress_rule_protocol":"icmp","sctp-b-ipv6-egress_action":"pass","sctp-a-ipv6-egress_action":"pass","Internal1_shared":"false","sctp-b-ipv6-ingress_rule_protocol":"any","Internal2_net_cidr_len":"17","sctp-a-name":"epc-sctp-a-ipv4v6-sec-group","sctp-a-ingress-src_end_port":"65535.0","sctp-b-ipv6-ingress_src_subnet_prefix":"0.0.0.0","sctp-a-egress-dst_end_port":"65535.0","sctp-a-ingress_action":"pass","sctp-b-egress_rule_protocol":"icmp","sctp-b-ipv6-ingress_action":"pass","vlc_st_service_type":"firewall","sctp-b-ipv6-egress_dst_end_port":"65535","sctp-b-ipv6-ingress-dst_start_port":"0","vlc2_Internal2_mac":"00:80:37:0E:02:12","vlc_st_availability_zone":"true","fsb_volume_image_name_1":"MME_FSB2_16ACP04_GA.qcow2","sctp-b-ingress-src_subnet_prefix":"0.0.0.0","sctp-a-ipv6-ingress_src_subnet_prefix_len":"0","Internal1_allow_transit":"true","gpb_flavor_name":"nv.c20r64d1","availability_zone_max_count":"1","fsb_volume_image_name_0":"MME_FSB1_16ACP04_GA.qcow2","sctp-b-ipv6-ingress_dst_addresses":"local","sctp-b-ipv6-egress_dst_subnet_prefix":"0.0.0.0","sctp-b-ipv6-ingress_ethertype":"IPv4","vlc1_Internal2_mac":"00:80:37:0E:01:12","sctp-a-ingress-src_subnet_prefix":"0.0.0.0","sctp-a-ipv6-ingress_action":"pass","Internal1_rpf":"disable","sctp-b-ingress_ethertype":"IPv4","sctp-b-egress_rule_application":"any","sctp-b-ingress-src_end_port":"65535.0","sctp-a-ipv6-ingress_rule_protocol":"any","sctp-a-ingress-src_start_port":"0.0","sctp-b-egress-dst_end_port":"65535.0"},"type":"VF","modelCustomizationName":"VF_vMee 0","vfModules":{"vf_vmee0..VfVmee..vmme_vlc..module-1":{"uuid":"522159d5-d6e0-4c2a-aa44-5a542a12a830","invariantUuid":"98a7c88b-b577-476a-90e4-e25a5871e02b","customizationUuid":"55b1be94-671a-403e-a26c-667e9c47d091","description":null,"name":"VfVmee..vmme_vlc..module-1","version":"2","modelCustomizationName":"VfVmee..vmme_vlc..module-1","properties":{"minCountInstances":0,"maxCountInstances":null,"initialCount":0,"vfModuleLabel":"vmme_vlc"},"inputs":{},"volumeGroupAllowed":false},"vf_vmee0..VfVmee..vmme_gpb..module-2":{"uuid":"41708296-e443-4c71-953f-d9a010f059e1","invariantUuid":"1cca90b8-3490-495e-87da-3f3e4c57d5b9","customizationUuid":"6add59e0-7fe1-4bc4-af48-f8812422ae7c","description":null,"name":"VfVmee..vmme_gpb..module-2","version":"2","modelCustomizationName":"VfVmee..vmme_gpb..module-2","properties":{"minCountInstances":0,"maxCountInstances":null,"initialCount":0,"vfModuleLabel":"vmme_gpb"},"inputs":{},"volumeGroupAllowed":false},"vf_vmee0..VfVmee..base_vmme..module-0":{"uuid":"a27f5cfc-7f12-4f99-af08-0af9c3885c87","invariantUuid":"a6f9e51a-2b35-416a-ae15-15e58d61f36d","customizationUuid":"f8c040f1-7e51-4a11-aca8-acf256cfd861","description":null,"name":"VfVmee..base_vmme..module-0","version":"2","modelCustomizationName":"VfVmee..base_vmme..module-0","properties":{"minCountInstances":1,"maxCountInstances":1,"initialCount":1,"vfModuleLabel":"base_vmme"},"inputs":{},"volumeGroupAllowed":true}},"volumeGroups":{"vf_vmee0..VfVmee..base_vmme..module-0":{"uuid":"a27f5cfc-7f12-4f99-af08-0af9c3885c87","invariantUuid":"a6f9e51a-2b35-416a-ae15-15e58d61f36d","customizationUuid":"f8c040f1-7e51-4a11-aca8-acf256cfd861","description":null,"name":"VfVmee..base_vmme..module-0","version":"2","modelCustomizationName":"VfVmee..base_vmme..module-0","properties":{"minCountInstances":1,"maxCountInstances":1,"initialCount":1,"vfModuleLabel":"base_vmme"},"inputs":{}}},"vfcInstanceGroups":{}}},"networks":{"ExtVL 0":{"uuid":"ddc3f20c-08b5-40fd-af72-c6d14636b986","invariantUuid":"379f816b-a7aa-422f-be30-17114ff50b7c","description":"ECOMP generic virtual link (network) base type for all other service-level and global networks","name":"ExtVL","version":"37.0","customizationUuid":"94fdd893-4a36-4d70-b16a-ec29c54c184f","inputs":{},"commands":{},"properties":{"network_assignments":"{is_external_network=false, ipv4_subnet_default_assignment={min_subnets_count=1}, ecomp_generated_network_assignment=false, ipv6_subnet_default_assignment={min_subnets_count=1}}","exVL_naming":"{ecomp_generated_naming=true}","network_flows":"{is_network_policy=false, is_bound_to_vpn=false}","network_homing":"{ecomp_selected_instance_node_target=false}"},"type":"VL","modelCustomizationName":"ExtVL 0"}},"collectionResource":{},"configurations":{"Port Mirroring Configuration By Policy 0":{"uuid":"b4398538-e89d-4f13-b33d-ca323434ba50","invariantUuid":"6ef0ca40-f366-4897-951f-abd65d25f6f7","description":"A port mirroring configuration by policy object","name":"Port Mirroring Configuration By Policy","version":"27.0","customizationUuid":"3c3b7b8d-8669-4b3b-8664-61970041fad2","inputs":{},"commands":{},"properties":{},"type":"Configuration","modelCustomizationName":"Port Mirroring Configuration By Policy 0","sourceNodes":[],"collectorNodes":null,"configurationByPolicy":false}},"serviceProxies":{},"vfModules":{"vf_vmee0..VfVmee..vmme_vlc..module-1":{"uuid":"522159d5-d6e0-4c2a-aa44-5a542a12a830","invariantUuid":"98a7c88b-b577-476a-90e4-e25a5871e02b","customizationUuid":"55b1be94-671a-403e-a26c-667e9c47d091","description":null,"name":"VfVmee..vmme_vlc..module-1","version":"2","modelCustomizationName":"VfVmee..vmme_vlc..module-1","properties":{"minCountInstances":0,"maxCountInstances":null,"initialCount":0,"vfModuleLabel":"vmme_vlc"},"inputs":{},"volumeGroupAllowed":false},"vf_vmee0..VfVmee..vmme_gpb..module-2":{"uuid":"41708296-e443-4c71-953f-d9a010f059e1","invariantUuid":"1cca90b8-3490-495e-87da-3f3e4c57d5b9","customizationUuid":"6add59e0-7fe1-4bc4-af48-f8812422ae7c","description":null,"name":"VfVmee..vmme_gpb..module-2","version":"2","modelCustomizationName":"VfVmee..vmme_gpb..module-2","properties":{"minCountInstances":0,"maxCountInstances":null,"initialCount":0,"vfModuleLabel":"vmme_gpb"},"inputs":{},"volumeGroupAllowed":false},"vf_vmee0..VfVmee..base_vmme..module-0":{"uuid":"a27f5cfc-7f12-4f99-af08-0af9c3885c87","invariantUuid":"a6f9e51a-2b35-416a-ae15-15e58d61f36d","customizationUuid":"f8c040f1-7e51-4a11-aca8-acf256cfd861","description":null,"name":"VfVmee..base_vmme..module-0","version":"2","modelCustomizationName":"VfVmee..base_vmme..module-0","properties":{"minCountInstances":1,"maxCountInstances":1,"initialCount":1,"vfModuleLabel":"base_vmme"},"inputs":{},"volumeGroupAllowed":true}},"volumeGroups":{"vf_vmee0..VfVmee..base_vmme..module-0":{"uuid":"a27f5cfc-7f12-4f99-af08-0af9c3885c87","invariantUuid":"a6f9e51a-2b35-416a-ae15-15e58d61f36d","customizationUuid":"f8c040f1-7e51-4a11-aca8-acf256cfd861","description":null,"name":"VfVmee..base_vmme..module-0","version":"2","modelCustomizationName":"VfVmee..base_vmme..module-0","properties":{"minCountInstances":1,"maxCountInstances":1,"initialCount":1,"vfModuleLabel":"base_vmme"},"inputs":{}}},"pnfs":{}}}');
+ }
+});
diff --git a/vid-webpack-master/src/app/shared/pipes/serviceInfo/serviceInfo.pipe.ts b/vid-webpack-master/src/app/shared/pipes/serviceInfo/serviceInfo.pipe.ts
new file mode 100644
index 000000000..8cb2e1dcd
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/pipes/serviceInfo/serviceInfo.pipe.ts
@@ -0,0 +1,13 @@
+import {PipeTransform, Pipe} from '@angular/core';
+import {isNullOrUndefined} from "util";
+
+@Pipe({ name: 'serviceInfo'})
+export class ServiceInfoPipe implements PipeTransform {
+ transform(service: string, store : any , modelId : string, fieldName : string): string {
+ const serviceHierarchy = store.getState().service.serviceHierarchy;
+ if(!isNullOrUndefined(serviceHierarchy) && !isNullOrUndefined(serviceHierarchy[modelId])){
+ return serviceHierarchy[modelId].service[fieldName] || null;
+ }
+ return null;
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/server/healthStatusService/health-status.service.spec.ts b/vid-webpack-master/src/app/shared/server/healthStatusService/health-status.service.spec.ts
new file mode 100644
index 000000000..36f6349e2
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/server/healthStatusService/health-status.service.spec.ts
@@ -0,0 +1,60 @@
+import {TestBed, inject, getTestBed} from '@angular/core/testing';
+
+import { HealthStatusService } from './health-status.service';
+import {Constants} from "../../utils/constants";
+import {HttpClientTestingModule, HttpTestingController} from "@angular/common/http/testing";
+import {ExternalComponentStatus} from "../../models/externalComponentStatus";
+
+describe('HealthStatusService', () => {
+
+ let injector;
+ let service: HealthStatusService;
+ let httpMock: HttpTestingController;
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({
+ imports: [HttpClientTestingModule],
+ providers: [HealthStatusService]
+ });
+
+ injector = getTestBed();
+ service = injector.get(HealthStatusService);
+ httpMock = injector.get(HttpTestingController);
+ });
+
+ describe('#getProbe', () =>{
+ it('when call probe, there is http GET with right url', () => {
+
+ service.getProbe().subscribe((result: Array<ExternalComponentStatus>)=>{
+ expect(result[0].component).toEqual("AAI");
+ expect(result[0].available).toBeTruthy();
+ expect(result[0].metadata).toEqual({ myKey: 'myValue' });
+
+ expect(result[1].component).toEqual("MSO");
+ expect(result[1].available).toBeFalsy();
+ expect(result[1].metadata).toEqual({otherKey: 123});
+ });
+
+ const req = httpMock.expectOne(Constants.Path.SERVICES_PROBE_PATH);
+ expect(req.request.method).toEqual('GET');
+ req.flush([
+ {
+ "component": "AAI",
+ "available": true,
+ "metadata": {
+ "myKey": "myValue"
+ }
+ },
+ {
+ "component": "MSO",
+ "available": false,
+ "metadata": {
+ "otherKey": 123
+ }
+ },
+ ]);
+ });
+
+ });
+
+});
diff --git a/vid-webpack-master/src/app/shared/server/healthStatusService/health-status.service.ts b/vid-webpack-master/src/app/shared/server/healthStatusService/health-status.service.ts
new file mode 100644
index 000000000..4305ab97e
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/server/healthStatusService/health-status.service.ts
@@ -0,0 +1,17 @@
+import { Injectable } from '@angular/core';
+import {HttpClient} from "@angular/common/http";
+import {Observable} from "rxjs/Observable";
+import {Constants} from "../../utils/constants";
+import {ExternalComponentStatus} from "../../models/externalComponentStatus";
+
+@Injectable()
+export class HealthStatusService {
+
+ constructor(private _http: HttpClient) {
+ }
+
+ getProbe(): Observable<Array<ExternalComponentStatus>> {
+ let pathQuery = Constants.Path.SERVICES_PROBE_PATH;
+ return this._http.get<Array<ExternalComponentStatus>>(pathQuery).map(res => res);
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/server/serviceInfo/AuditStatus.model.ts b/vid-webpack-master/src/app/shared/server/serviceInfo/AuditStatus.model.ts
new file mode 100644
index 000000000..0b4c70f9d
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/server/serviceInfo/AuditStatus.model.ts
@@ -0,0 +1,10 @@
+export class AuditStatus{
+ id: number;
+ createdDate: number;
+ final: boolean;
+ jobId :string;
+ jobStatus :string;
+ source: string;
+ requestId: string;
+ additionalInfo :any
+}
diff --git a/vid-webpack-master/src/app/shared/server/serviceInfo/serviceInfo.model.ts b/vid-webpack-master/src/app/shared/server/serviceInfo/serviceInfo.model.ts
new file mode 100644
index 000000000..0b4695930
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/server/serviceInfo/serviceInfo.model.ts
@@ -0,0 +1,38 @@
+import {ServiceStatus} from '../../../instantiationStatus/instantiationStatus.component.service';
+
+export class ServiceInfoModel {
+ id: number;
+ created: Date;
+ modified: Date;
+ createdId: number;
+ modifiedId: number;
+ numRow: number;
+ uuid: string;
+ userId: string;
+ jobStatus: string;
+ pause: boolean;
+ owningEntityId: string;
+ owningEntityName: string;
+ project: string;
+ aicZoneId: string;
+ aicZoneName: string;
+ tenantId: string;
+ tenantName: string;
+ regionId: string;
+ regionName: string;
+ serviceType: string;
+ subscriberName: string;
+ serviceInstanceId: string;
+ serviceInstanceName: string;
+ serviceModelId: string;
+ serviceModelName: string;
+ serviceModelVersion: string;
+ templateId: string;
+ auditUserId: string;
+ jobId: string;
+}
+
+export class ServiceInfoUiModel extends ServiceInfoModel{
+ serviceStatus : ServiceStatus;
+ serviceIndex : number;
+}
diff --git a/vid-webpack-master/src/app/shared/server/serviceInfo/serviceInfo.service.spec.ts b/vid-webpack-master/src/app/shared/server/serviceInfo/serviceInfo.service.spec.ts
new file mode 100644
index 000000000..78c1b5ab9
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/server/serviceInfo/serviceInfo.service.spec.ts
@@ -0,0 +1,235 @@
+import {getTestBed, TestBed} from '@angular/core/testing';
+import {HttpClientTestingModule, HttpTestingController} from '@angular/common/http/testing';
+import {ServiceInfoService} from './serviceInfo.service';
+import {ServiceInfoModel} from './serviceInfo.model';
+import {Constants} from "../../utils/constants";
+
+describe('Service Info Service', () => {
+ let injector;
+ let service: ServiceInfoService;
+ let httpMock: HttpTestingController;
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({
+ imports: [HttpClientTestingModule],
+ providers: [ServiceInfoService]
+ });
+
+ injector = getTestBed();
+ service = injector.get(ServiceInfoService);
+ httpMock = injector.get(HttpTestingController);
+ });
+
+ describe('#getServicesJobInfo', () => {
+ it('should return an Observable<ServiceInfoModel[]>', () => {
+ const dummyServiceInfo: ServiceInfoModel[] = generateServiceInfoData();
+
+ service.getServicesJobInfo(true).subscribe((serviceInfo:Array<ServiceInfoModel>) => {
+ expect(serviceInfo).toEqual(dummyServiceInfo);
+ });
+ });
+
+
+ });
+
+ describe('#deleteJob', () =>{
+ it('delete job', () => {
+ const jobId : string = "1111";
+
+ service.deleteJob(jobId).subscribe();
+
+ const req = httpMock.expectOne(Constants.Path.SERVICES_JOB_INFO_PATH + '/job/' + jobId);
+ expect(req.request.method).toEqual('DELETE');
+
+ });
+ });
+
+ describe('#hideJob', () =>{
+ it('when call hide job, there is http POST with right url', () => {
+ const jobId : string = "3";
+
+ service.hideJob(jobId).subscribe();
+
+ const req = httpMock.expectOne(Constants.Path.SERVICES_JOB_INFO_PATH + '/hide/' + jobId);
+ expect(req.request.method).toEqual('POST');
+ });
+ });
+
+ describe('#getJobAuditStatus', ()=> {
+ it('should return Observable<Object[]>', ()=>{
+ const jobId : string = '111';
+
+ service.getJobAuditStatus(jobId).subscribe();
+ const req = httpMock.expectOne(Constants.Path.SERVICES_JOB_INFO_PATH + Constants.Path.SERVICES_JOB_AUDIT_PATH + '/' + jobId + '?source=VID');
+ const req2 = httpMock.expectOne(Constants.Path.SERVICES_JOB_INFO_PATH + Constants.Path.SERVICES_JOB_AUDIT_PATH + '/' + jobId + '?source=MSO');
+
+ expect(req.request.method).toEqual('GET');
+ expect(req2.request.method).toEqual('GET');
+ });
+ });
+
+ function generateServiceInfoData(){
+ return <ServiceInfoModel[]>JSON.parse(JSON.stringify(
+ [{
+ "created": 1519956533000,
+ "modified": 1521727738000,
+ "createdId": null,
+ "modifiedId": null,
+ "rowNum": null,
+ "auditUserId": null,
+ "auditTrail": null,
+ "jobId": "6748648484",
+ "userId": "2222",
+ "jobStatus": "FAILED",
+ "pause": false,
+ "owningEntityId": "1234",
+ "owningEntityName": null,
+ "project": null,
+ "aicZoneId": null,
+ "aicZoneName": null,
+ "tenantId": null,
+ "tenantName": null,
+ "regionId": null,
+ "regionName": null,
+ "serviceType": null,
+ "subscriberName": null,
+ "serviceInstanceId": "1",
+ "serviceInstanceName": null,
+ "serviceModelId": null,
+ "serviceModelName": null,
+ "serviceModelVersion": null,
+ "createdBulkDate": 1519956533000,
+ "statusModifiedDate": 1520042933000,
+ "hidden": false
+ },
+ {
+ "created": 1519956533000,
+ "modified": 1521727738000,
+ "createdId": null,
+ "modifiedId": null,
+ "rowNum": null,
+ "auditUserId": null,
+ "auditTrail": null,
+ "jobId": "6748648484",
+ "userId": "2222",
+ "jobStatus": "FAILED",
+ "pause": false,
+ "owningEntityId": "1234",
+ "owningEntityName": null,
+ "project": null,
+ "aicZoneId": null,
+ "aicZoneName": null,
+ "tenantId": null,
+ "tenantName": null,
+ "regionId": null,
+ "regionName": null,
+ "serviceType": null,
+ "subscriberName": null,
+ "serviceInstanceId": "1",
+ "serviceInstanceName": null,
+ "serviceModelId": null,
+ "serviceModelName": null,
+ "serviceModelVersion": null,
+ "createdBulkDate": 1519956533000,
+ "statusModifiedDate": 1520042933000,
+ "hidden": false
+ },
+ {
+ "created": 1519956533000,
+ "modified": 1521727738000,
+ "createdId": null,
+ "modifiedId": null,
+ "rowNum": null,
+ "auditUserId": null,
+ "auditTrail": null,
+ "jobId": "6748648484",
+ "userId": "2222",
+ "jobStatus": "FAILED",
+ "pause": false,
+ "owningEntityId": "1234",
+ "owningEntityName": null,
+ "project": null,
+ "aicZoneId": null,
+ "aicZoneName": null,
+ "tenantId": null,
+ "tenantName": null,
+ "regionId": null,
+ "regionName": null,
+ "serviceType": null,
+ "subscriberName": null,
+ "serviceInstanceId": "2",
+ "serviceInstanceName": null,
+ "serviceModelId": null,
+ "serviceModelName": null,
+ "serviceModelVersion": null,
+ "createdBulkDate": 1519956533000,
+ "statusModifiedDate": 1520042933000,
+ "hidden": false
+ },
+ {
+ "created": 1519956533000,
+ "modified": 1521727738000,
+ "createdId": null,
+ "modifiedId": null,
+ "rowNum": null,
+ "auditUserId": null,
+ "auditTrail": null,
+ "jobId": "6748648484",
+ "userId": "2222",
+ "jobStatus": "FAILED",
+ "pause": false,
+ "owningEntityId": "1234",
+ "owningEntityName": null,
+ "project": null,
+ "aicZoneId": null,
+ "aicZoneName": null,
+ "tenantId": null,
+ "tenantName": null,
+ "regionId": null,
+ "regionName": null,
+ "serviceType": null,
+ "subscriberName": null,
+ "serviceInstanceId": "2",
+ "serviceInstanceName": null,
+ "serviceModelId": null,
+ "serviceModelName": null,
+ "serviceModelVersion": null,
+ "createdBulkDate": 1519956533000,
+ "statusModifiedDate": 1520042933000,
+ "hidden": false
+ },
+ {
+ "created": 1519956533000,
+ "modified": 1521727738000,
+ "createdId": null,
+ "modifiedId": null,
+ "rowNum": null,
+ "auditUserId": null,
+ "auditTrail": null,
+ "jobId": "6748648484",
+ "userId": "2222",
+ "jobStatus": "FAILED",
+ "pause": false,
+ "owningEntityId": "1234",
+ "owningEntityName": null,
+ "project": null,
+ "aicZoneId": null,
+ "aicZoneName": null,
+ "tenantId": null,
+ "tenantName": null,
+ "regionId": null,
+ "regionName": null,
+ "serviceType": null,
+ "subscriberName": null,
+ "serviceInstanceId": "3",
+ "serviceInstanceName": null,
+ "serviceModelId": null,
+ "serviceModelName": null,
+ "serviceModelVersion": null,
+ "createdBulkDate": 1519956533000,
+ "statusModifiedDate": 1520042933000,
+ "hidden": false
+ }]
+ ));
+ }
+});
diff --git a/vid-webpack-master/src/app/shared/server/serviceInfo/serviceInfo.service.ts b/vid-webpack-master/src/app/shared/server/serviceInfo/serviceInfo.service.ts
new file mode 100644
index 000000000..e0057bb4d
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/server/serviceInfo/serviceInfo.service.ts
@@ -0,0 +1,38 @@
+import {Injectable} from '@angular/core';
+import {Observable} from 'rxjs/Observable';
+import {ServiceInfoModel} from './serviceInfo.model';
+import {HttpClient} from '@angular/common/http';
+import 'rxjs/add/operator/map'
+import {Constants} from '../../utils/constants';
+import {forkJoin} from "rxjs/observable/forkJoin";
+
+@Injectable()
+export class ServiceInfoService {
+ constructor(private _http: HttpClient) {
+ }
+
+ getServicesJobInfo(filterByUser : boolean): Observable<ServiceInfoModel[]> {
+ let pathQuery = Constants.Path.SERVICES_JOB_INFO_PATH;
+ return this._http.get<ServiceInfoModel[]>(pathQuery).map(res => res );
+ }
+
+ deleteJob(jobId: string): Observable<any> {
+ let pathQuery = Constants.Path.SERVICES_JOB_INFO_PATH + '/job/' + jobId;
+ return this._http.delete<any>(pathQuery).map(res => res);
+ }
+
+ hideJob(jobId: string): Observable<any> {
+ let pathQuery = Constants.Path.SERVICES_JOB_INFO_PATH + '/hide/' + jobId;
+ return this._http.post<any>(pathQuery, null).map(res => res);
+ }
+
+ getJobAuditStatus(jobId : string) : Observable<Object[]>{
+ let pathQueryVID = Constants.Path.SERVICES_JOB_INFO_PATH + Constants.Path.SERVICES_JOB_AUDIT_PATH + '/' + jobId + '?source=VID';
+ let pathQueryMSO = Constants.Path.SERVICES_JOB_INFO_PATH + Constants.Path.SERVICES_JOB_AUDIT_PATH + '/' + jobId + '?source=MSO';
+
+ let vidObs = this._http.get(pathQueryVID);
+ let msoObs = this._http.get(pathQueryMSO);
+ return forkJoin([vidObs, msoObs]);
+ }
+
+}
diff --git a/vid-webpack-master/src/app/shared/services/defaultDataServiceGenerator/default.data.generator.service.spec.ts b/vid-webpack-master/src/app/shared/services/defaultDataServiceGenerator/default.data.generator.service.spec.ts
new file mode 100644
index 000000000..617dbd3da
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/services/defaultDataServiceGenerator/default.data.generator.service.spec.ts
@@ -0,0 +1,73 @@
+import { getTestBed, TestBed } from '@angular/core/testing';
+import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
+import { NgRedux } from '@angular-redux/store';
+import { DefaultDataGeneratorService } from './default.data.generator.service';
+
+export class MockAppStore<T> {}
+
+describe('Default Data Generator Service', () => {
+ let injector;
+ let service: DefaultDataGeneratorService;
+ let httpMock: HttpTestingController;
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({
+ imports: [HttpClientTestingModule],
+ providers: [DefaultDataGeneratorService,
+ {provide: NgRedux, useClass: MockAppStore}]
+ });
+
+ injector = getTestBed();
+ service = injector.get(DefaultDataGeneratorService);
+ httpMock = injector.get(HttpTestingController);
+ });
+
+ it('generateVFModule should create vf module object', () => {
+ const serviceHierarchy = generateServiceHierarchy();
+ const vnfUUID: string = 'VF_vMee 0';
+ const vnfModuleUUID: string = 'vf_vmee0..VfVmee..base_vmme..module-0';
+
+ let result = service.generateVFModule(serviceHierarchy, vnfUUID, vnfModuleUUID);
+
+ expect(result.modelInfo.modelType).toEqual('VFmodule');
+ expect(result.modelInfo.modelInvariantId).toEqual(serviceHierarchy.vnfs[vnfUUID].vfModules[vnfModuleUUID].invariantUuid);
+ expect(result.modelInfo.modelVersionId).toEqual(serviceHierarchy.vnfs[vnfUUID].vfModules[vnfModuleUUID].uuid);
+ expect(result.modelInfo.modelName).toEqual(serviceHierarchy.vnfs[vnfUUID].vfModules[vnfModuleUUID].name);
+ expect(result.modelInfo.modelVersion).toEqual(serviceHierarchy.vnfs[vnfUUID].vfModules[vnfModuleUUID].version);
+ expect(result.modelInfo.modelCustomizationId).toEqual(serviceHierarchy.vnfs[vnfUUID].vfModules[vnfModuleUUID].customizationUuid);
+ expect(result.modelInfo.modelCustomizationName).toEqual(serviceHierarchy.vnfs[vnfUUID].vfModules[vnfModuleUUID].modelCustomizationName);
+ expect(result.sdncPreReload).toBeNull();
+ });
+
+ it('generateVNFData should create vnf object', () => {
+ const serviceHierarchy = generateServiceHierarchy();
+ const vnfName: string = 'VF_vMee 0';
+ const formValues = generateVNFFormValues();
+ const vfUUID: string = 'vf_vmee0..VfVmee..base_vmme..module-0';
+
+ let result = service.generateVNFData(serviceHierarchy, vnfName, vfUUID, formValues);
+
+ expect(result.productFamilyId).toEqual(formValues.productFamilyId);
+ expect(result.lcpCloudRegionId).toBeNull();
+ expect(result.tenantId).toBeNull();
+ expect(result.lineOfBusiness).toBeNull();
+ expect(result.platformName).toBeNull();
+ expect(result.modelInfo.modelType).toEqual('VF');
+ expect(result.modelInfo.modelInvariantId).toEqual(serviceHierarchy.vnfs[vnfName].invariantUuid);
+ expect(result.modelInfo.modelVersionId).toEqual(formValues.modelInfo.modelVersionId);
+ expect(result.modelInfo.modelName).toEqual(serviceHierarchy.vnfs[vnfName].name);
+ expect(result.modelInfo.modelVersion).toEqual(serviceHierarchy.vnfs[vnfName].version);
+ expect(result.modelInfo.modelCustomizationId).toEqual(serviceHierarchy.vnfs[vnfName].modelCustomizationId);
+ expect(result.modelInfo.modelCustomizationName).toEqual(serviceHierarchy.vnfs[vnfName].modelCustomizationName);
+ });
+});
+
+
+function generateServiceHierarchy() {
+ return JSON.parse('{"service":{"uuid":"6e59c5de-f052-46fa-aa7e-2fca9d674c44","invariantUuid":"e49fbd11-e60c-4a8e-b4bf-30fbe8f4fcc0","name":"ComplexService","version":"1.0","toscaModelURL":null,"category":"Mobility","serviceType":"","serviceRole":"","description":"ComplexService","serviceEcompNaming":"true","instantiationType":"Macro","inputs":{}},"vnfs":{"VF_vMee 0":{"uuid":"d6557200-ecf2-4641-8094-5393ae3aae60","invariantUuid":"4160458e-f648-4b30-a176-43881ffffe9e","description":"VSP_vMee","name":"VF_vMee","version":"2.0","customizationUuid":"91415b44-753d-494c-926a-456a9172bbb9","inputs":{},"commands":{},"properties":{"gpb2_Internal2_mac":"00:80:37:0E:02:22","sctp-b-ipv6-egress_src_start_port":"0","sctp-a-ipv6-egress_rule_application":"any","Internal2_allow_transit":"true","sctp-b-IPv6_ethertype":"IPv6","sctp-a-egress_rule_application":"any","sctp-b-ingress_action":"pass","sctp-b-ingress_rule_protocol":"icmp","ncb2_Internal1_mac":"00:80:37:0E:0F:12","sctp-b-ipv6-ingress-src_start_port":"0.0","ncb1_Internal2_mac":"00:80:37:0E:09:12","fsb_volume_size_0":"320.0","sctp-b-egress_src_addresses":"local","sctp-a-ipv6-ingress_ethertype":"IPv4","sctp-a-ipv6-ingress-dst_start_port":"0","sctp-b-ipv6-ingress_rule_application":"any","domain_name":"default-domain","sctp-a-ingress_rule_protocol":"icmp","sctp-b-egress-src_start_port":"0.0","sctp-a-egress_src_addresses":"local","sctp-b-display_name":"epc-sctp-b-ipv4v6-sec-group","sctp-a-egress-src_start_port":"0.0","sctp-a-ingress_ethertype":"IPv4","sctp-b-ipv6-ingress-dst_end_port":"65535","sctp-b-dst_subnet_prefix_v6":"::","nf_naming":"{ecomp_generated_naming=true}","sctp-a-ipv6-ingress_src_subnet_prefix":"0.0.0.0","sctp-b-egress-dst_start_port":"0.0","ncb_flavor_name":"nv.c20r64d1","gpb1_Internal1_mac":"00:80:37:0E:01:22","sctp-b-egress_dst_subnet_prefix_len":"0.0","Internal2_net_cidr":"169.255.0.0","sctp-a-ingress-dst_start_port":"0.0","sctp-a-egress-dst_start_port":"0.0","fsb1_Internal2_mac":"00:80:37:0E:0B:12","sctp-a-egress_ethertype":"IPv4","vlc_st_service_mode":"in-network-nat","sctp-a-ipv6-egress_ethertype":"IPv4","sctp-a-egress-src_end_port":"65535.0","sctp-b-ipv6-egress_rule_application":"any","sctp-b-egress_action":"pass","sctp-a-ingress-src_subnet_prefix_len":"0.0","sctp-b-ipv6-ingress-src_end_port":"65535.0","sctp-b-name":"epc-sctp-b-ipv4v6-sec-group","fsb2_Internal1_mac":"00:80:37:0E:0D:12","sctp-a-ipv6-ingress-src_start_port":"0.0","sctp-b-ipv6-egress_ethertype":"IPv4","Internal1_net_cidr":"169.253.0.0","sctp-a-egress_dst_subnet_prefix":"0.0.0.0","fsb_flavor_name":"nv.c20r64d1","sctp_rule_protocol":"132","sctp-b-ipv6-ingress_src_subnet_prefix_len":"0","sctp-a-ipv6-ingress_rule_application":"any","ecomp_generated_naming":"true","sctp-a-IPv6_ethertype":"IPv6","vlc2_Internal1_mac":"00:80:37:0E:02:12","vlc_st_virtualization_type":"virtual-machine","sctp-b-ingress-dst_start_port":"0.0","sctp-b-ingress-dst_end_port":"65535.0","sctp-a-ipv6-ingress-src_end_port":"65535.0","sctp-a-display_name":"epc-sctp-a-ipv4v6-sec-group","sctp-b-ingress_rule_application":"any","int2_sec_group_name":"int2-sec-group","vlc_flavor_name":"nd.c16r64d1","sctp-b-ipv6-egress_src_addresses":"local","vlc_st_interface_type_int1":"other1","sctp-b-egress-src_end_port":"65535.0","sctp-a-ipv6-egress-dst_start_port":"0","vlc_st_interface_type_int2":"other2","sctp-a-ipv6-egress_rule_protocol":"any","Internal2_shared":"false","sctp-a-ipv6-egress_dst_subnet_prefix_len":"0","Internal2_rpf":"disable","vlc1_Internal1_mac":"00:80:37:0E:01:12","sctp-b-ipv6-egress_src_end_port":"65535","sctp-a-ipv6-egress_src_addresses":"local","sctp-a-ingress-dst_end_port":"65535.0","sctp-a-ipv6-egress_src_end_port":"65535","Internal1_forwarding_mode":"l2","Internal2_dhcp":"false","sctp-a-dst_subnet_prefix_v6":"::","pxe_image_name":"MME_PXE-Boot_16ACP04_GA.qcow2","vlc_st_interface_type_gtp":"other0","ncb1_Internal1_mac":"00:80:37:0E:09:12","sctp-b-src_subnet_prefix_v6":"::","sctp-a-egress_dst_subnet_prefix_len":"0.0","int1_sec_group_name":"int1-sec-group","Internal1_dhcp":"false","sctp-a-ipv6-egress_dst_end_port":"65535","Internal2_forwarding_mode":"l2","fsb2_Internal2_mac":"00:80:37:0E:0D:12","sctp-b-egress_dst_subnet_prefix":"0.0.0.0","Internal1_net_cidr_len":"17","gpb2_Internal1_mac":"00:80:37:0E:02:22","sctp-b-ingress-src_subnet_prefix_len":"0.0","sctp-a-ingress_dst_addresses":"local","sctp-a-egress_action":"pass","fsb_volume_type_0":"SF-Default-SSD","ncb2_Internal2_mac":"00:80:37:0E:0F:12","vlc_st_interface_type_sctp_a":"left","vlc_st_interface_type_sctp_b":"right","sctp-a-src_subnet_prefix_v6":"::","vlc_st_version":"2","sctp-b-egress_ethertype":"IPv4","sctp-a-ingress_rule_application":"any","gpb1_Internal2_mac":"00:80:37:0E:01:22","instance_ip_family_v6":"v6","sctp-a-ipv6-egress_src_start_port":"0","sctp-b-ingress-src_start_port":"0.0","sctp-b-ingress_dst_addresses":"local","fsb1_Internal1_mac":"00:80:37:0E:0B:12","vlc_st_interface_type_oam":"management","multi_stage_design":"false","oam_sec_group_name":"oam-sec-group","Internal2_net_gateway":"169.255.0.3","sctp-a-ipv6-ingress-dst_end_port":"65535","sctp-b-ipv6-egress-dst_start_port":"0","Internal1_net_gateway":"169.253.0.3","sctp-b-ipv6-egress_rule_protocol":"any","gtp_sec_group_name":"gtp-sec-group","sctp-a-ipv6-egress_dst_subnet_prefix":"0.0.0.0","sctp-b-ipv6-egress_dst_subnet_prefix_len":"0","sctp-a-ipv6-ingress_dst_addresses":"local","sctp-a-egress_rule_protocol":"icmp","sctp-b-ipv6-egress_action":"pass","sctp-a-ipv6-egress_action":"pass","Internal1_shared":"false","sctp-b-ipv6-ingress_rule_protocol":"any","Internal2_net_cidr_len":"17","sctp-a-name":"epc-sctp-a-ipv4v6-sec-group","sctp-a-ingress-src_end_port":"65535.0","sctp-b-ipv6-ingress_src_subnet_prefix":"0.0.0.0","sctp-a-egress-dst_end_port":"65535.0","sctp-a-ingress_action":"pass","sctp-b-egress_rule_protocol":"icmp","sctp-b-ipv6-ingress_action":"pass","vlc_st_service_type":"firewall","sctp-b-ipv6-egress_dst_end_port":"65535","sctp-b-ipv6-ingress-dst_start_port":"0","vlc2_Internal2_mac":"00:80:37:0E:02:12","vlc_st_availability_zone":"true","fsb_volume_image_name_1":"MME_FSB2_16ACP04_GA.qcow2","sctp-b-ingress-src_subnet_prefix":"0.0.0.0","sctp-a-ipv6-ingress_src_subnet_prefix_len":"0","Internal1_allow_transit":"true","gpb_flavor_name":"nv.c20r64d1","availability_zone_max_count":"1","fsb_volume_image_name_0":"MME_FSB1_16ACP04_GA.qcow2","sctp-b-ipv6-ingress_dst_addresses":"local","sctp-b-ipv6-egress_dst_subnet_prefix":"0.0.0.0","sctp-b-ipv6-ingress_ethertype":"IPv4","vlc1_Internal2_mac":"00:80:37:0E:01:12","sctp-a-ingress-src_subnet_prefix":"0.0.0.0","sctp-a-ipv6-ingress_action":"pass","Internal1_rpf":"disable","sctp-b-ingress_ethertype":"IPv4","sctp-b-egress_rule_application":"any","sctp-b-ingress-src_end_port":"65535.0","sctp-a-ipv6-ingress_rule_protocol":"any","sctp-a-ingress-src_start_port":"0.0","sctp-b-egress-dst_end_port":"65535.0"},"type":"VF","modelCustomizationName":"VF_vMee 0","vfModules":{"vf_vmee0..VfVmee..vmme_vlc..module-1":{"uuid":"522159d5-d6e0-4c2a-aa44-5a542a12a830","invariantUuid":"98a7c88b-b577-476a-90e4-e25a5871e02b","customizationUuid":"55b1be94-671a-403e-a26c-667e9c47d091","description":null,"name":"VfVmee..vmme_vlc..module-1","version":"2","modelCustomizationName":"VfVmee..vmme_vlc..module-1","properties":{"minCountInstances":0,"maxCountInstances":null,"initialCount":0,"vfModuleLabel":"vmme_vlc"},"inputs":{},"volumeGroupAllowed":false},"vf_vmee0..VfVmee..vmme_gpb..module-2":{"uuid":"41708296-e443-4c71-953f-d9a010f059e1","invariantUuid":"1cca90b8-3490-495e-87da-3f3e4c57d5b9","customizationUuid":"6add59e0-7fe1-4bc4-af48-f8812422ae7c","description":null,"name":"VfVmee..vmme_gpb..module-2","version":"2","modelCustomizationName":"VfVmee..vmme_gpb..module-2","properties":{"minCountInstances":0,"maxCountInstances":null,"initialCount":0,"vfModuleLabel":"vmme_gpb"},"inputs":{},"volumeGroupAllowed":false},"vf_vmee0..VfVmee..base_vmme..module-0":{"uuid":"a27f5cfc-7f12-4f99-af08-0af9c3885c87","invariantUuid":"a6f9e51a-2b35-416a-ae15-15e58d61f36d","customizationUuid":"f8c040f1-7e51-4a11-aca8-acf256cfd861","description":null,"name":"VfVmee..base_vmme..module-0","version":"2","modelCustomizationName":"VfVmee..base_vmme..module-0","properties":{"minCountInstances":1,"maxCountInstances":1,"initialCount":1,"vfModuleLabel":"base_vmme"},"inputs":{},"volumeGroupAllowed":true}},"volumeGroups":{"vf_vmee0..VfVmee..base_vmme..module-0":{"uuid":"a27f5cfc-7f12-4f99-af08-0af9c3885c87","invariantUuid":"a6f9e51a-2b35-416a-ae15-15e58d61f36d","customizationUuid":"f8c040f1-7e51-4a11-aca8-acf256cfd861","description":null,"name":"VfVmee..base_vmme..module-0","version":"2","modelCustomizationName":"VfVmee..base_vmme..module-0","properties":{"minCountInstances":1,"maxCountInstances":1,"initialCount":1,"vfModuleLabel":"base_vmme"},"inputs":{}}},"vfcInstanceGroups":{}}},"networks":{"ExtVL 0":{"uuid":"ddc3f20c-08b5-40fd-af72-c6d14636b986","invariantUuid":"379f816b-a7aa-422f-be30-17114ff50b7c","description":"ECOMP generic virtual link (network) base type for all other service-level and global networks","name":"ExtVL","version":"37.0","customizationUuid":"94fdd893-4a36-4d70-b16a-ec29c54c184f","inputs":{},"commands":{},"properties":{"network_assignments":"{is_external_network=false, ipv4_subnet_default_assignment={min_subnets_count=1}, ecomp_generated_network_assignment=false, ipv6_subnet_default_assignment={min_subnets_count=1}}","exVL_naming":"{ecomp_generated_naming=true}","network_flows":"{is_network_policy=false, is_bound_to_vpn=false}","network_homing":"{ecomp_selected_instance_node_target=false}"},"type":"VL","modelCustomizationName":"ExtVL 0"}},"collectionResource":{},"configurations":{"Port Mirroring Configuration By Policy 0":{"uuid":"b4398538-e89d-4f13-b33d-ca323434ba50","invariantUuid":"6ef0ca40-f366-4897-951f-abd65d25f6f7","description":"A port mirroring configuration by policy object","name":"Port Mirroring Configuration By Policy","version":"27.0","customizationUuid":"3c3b7b8d-8669-4b3b-8664-61970041fad2","inputs":{},"commands":{},"properties":{},"type":"Configuration","modelCustomizationName":"Port Mirroring Configuration By Policy 0","sourceNodes":[],"collectorNodes":null,"configurationByPolicy":false}},"serviceProxies":{},"vfModules":{"vf_vmee0..VfVmee..vmme_vlc..module-1":{"uuid":"522159d5-d6e0-4c2a-aa44-5a542a12a830","invariantUuid":"98a7c88b-b577-476a-90e4-e25a5871e02b","customizationUuid":"55b1be94-671a-403e-a26c-667e9c47d091","description":null,"name":"VfVmee..vmme_vlc..module-1","version":"2","modelCustomizationName":"VfVmee..vmme_vlc..module-1","properties":{"minCountInstances":0,"maxCountInstances":null,"initialCount":0,"vfModuleLabel":"vmme_vlc"},"inputs":{},"volumeGroupAllowed":false},"vf_vmee0..VfVmee..vmme_gpb..module-2":{"uuid":"41708296-e443-4c71-953f-d9a010f059e1","invariantUuid":"1cca90b8-3490-495e-87da-3f3e4c57d5b9","customizationUuid":"6add59e0-7fe1-4bc4-af48-f8812422ae7c","description":null,"name":"VfVmee..vmme_gpb..module-2","version":"2","modelCustomizationName":"VfVmee..vmme_gpb..module-2","properties":{"minCountInstances":0,"maxCountInstances":null,"initialCount":0,"vfModuleLabel":"vmme_gpb"},"inputs":{},"volumeGroupAllowed":false},"vf_vmee0..VfVmee..base_vmme..module-0":{"uuid":"a27f5cfc-7f12-4f99-af08-0af9c3885c87","invariantUuid":"a6f9e51a-2b35-416a-ae15-15e58d61f36d","customizationUuid":"f8c040f1-7e51-4a11-aca8-acf256cfd861","description":null,"name":"VfVmee..base_vmme..module-0","version":"2","modelCustomizationName":"VfVmee..base_vmme..module-0","properties":{"minCountInstances":1,"maxCountInstances":1,"initialCount":1,"vfModuleLabel":"base_vmme"},"inputs":{},"volumeGroupAllowed":true}},"volumeGroups":{"vf_vmee0..VfVmee..base_vmme..module-0":{"uuid":"a27f5cfc-7f12-4f99-af08-0af9c3885c87","invariantUuid":"a6f9e51a-2b35-416a-ae15-15e58d61f36d","customizationUuid":"f8c040f1-7e51-4a11-aca8-acf256cfd861","description":null,"name":"VfVmee..base_vmme..module-0","version":"2","modelCustomizationName":"VfVmee..base_vmme..module-0","properties":{"minCountInstances":1,"maxCountInstances":1,"initialCount":1,"vfModuleLabel":"base_vmme"},"inputs":{}}},"pnfs":{}}');
+}
+
+
+function generateVNFFormValues() {
+ return JSON.parse('{"globalSubscriberId":"e433710f-9217-458d-a79d-1c7aff376d89","productFamilyId":"vRRaaS","subscriptionServiceType":"VIRTUAL USP","lcpCloudRegionId":"mtn6","tenantId":"1178612d2b394be4834ad77f567c0af2","aicZoneId":"JAG1","projectName":"DFW","owningEntityId":"d61e6f2d-12fa-4cc2-91df-7c244011d6fc","rollbackOnFailure":"true","bulkSize":1,"instanceParams":[{}],"modelInfo":{"modelInvariantId":"e49fbd11-e60c-4a8e-b4bf-30fbe8f4fcc0","modelVersionId":"6e59c5de-f052-46fa-aa7e-2fca9d674c44","modelName":"ComplexService","modelVersion":"1.0"},"isUserProvidedNaming":false,"tenantName":"AIN Web Tool-15-D-SSPtestcustome","aicZoneName":"YUDFJULP-JAG1"}');
+}
diff --git a/vid-webpack-master/src/app/shared/services/defaultDataServiceGenerator/default.data.generator.service.ts b/vid-webpack-master/src/app/shared/services/defaultDataServiceGenerator/default.data.generator.service.ts
new file mode 100644
index 000000000..b1e676fc5
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/services/defaultDataServiceGenerator/default.data.generator.service.ts
@@ -0,0 +1,82 @@
+import { Injectable } from '@angular/core';
+import * as _ from 'lodash';
+import { createVFModuleInstance, updateVNFInstance } from '../../../service.actions';
+import { NgRedux } from '@angular-redux/store';
+import { AppState } from '../../../store/reducers';
+
+@Injectable()
+export class DefaultDataGeneratorService {
+ static controlsFieldsStatus = {};
+
+ constructor(private store: NgRedux<AppState>) { }
+
+ updateReduxOnFirstSet(serviceId: string, formServiceValues: any): void {
+ const serviceHierarchy = this.store.getState().service.serviceHierarchy[serviceId];
+ if (serviceHierarchy && !_.isEmpty(serviceHierarchy.vnfs)) {
+ for (let vnfUUID in serviceHierarchy.vnfs) {
+ for (let vnfModuleUUID in serviceHierarchy.vnfs[vnfUUID].vfModules) {
+ if (serviceHierarchy.vnfs[vnfUUID].vfModules[vnfModuleUUID].properties.minCountInstances > 0) {
+
+ let vfModule = this.generateVFModule(serviceHierarchy, vnfUUID, vnfModuleUUID);
+ this.updateVNFInstanceRedux(
+ serviceHierarchy.vnfs[vnfUUID].modelName,
+ serviceId,
+ serviceHierarchy.vnfs[vnfUUID].vfModules[vnfModuleUUID].properties.initialCount,
+ vfModule,
+ this.generateVNFData(serviceHierarchy, vnfUUID, vnfModuleUUID, formServiceValues),
+ vnfModuleUUID
+ );
+ }
+ }
+ }
+ }
+ }
+
+ updateVNFInstanceRedux(vnfModelName: string, serviceId: string, numberOfVfModules: number, vfModuleData: any, vnfData: any, vfModuleName : string): void {
+ if (numberOfVfModules > 0) {
+ this.store.dispatch(updateVNFInstance(vnfData, vnfData.modelInfo.modelCustomizationName, serviceId));
+ for (let i = 0; i < numberOfVfModules; i++) {
+ this.store.dispatch(createVFModuleInstance(vfModuleData, vfModuleName, serviceId));
+ }
+ }
+ }
+
+
+ generateVFModule(serviceHierarchy: any, vnfUUID: string, vnfModuleUUID: string) {
+ return {
+ 'sdncPreReload': null,
+ 'modelInfo': {
+ 'modelType': 'VFmodule',
+ 'modelInvariantId': serviceHierarchy.vnfs[vnfUUID].vfModules[vnfModuleUUID].invariantUuid,
+ 'modelVersionId': serviceHierarchy.vnfs[vnfUUID].vfModules[vnfModuleUUID].uuid,
+ 'modelName': serviceHierarchy.vnfs[vnfUUID].vfModules[vnfModuleUUID].name,
+ 'modelVersion': serviceHierarchy.vnfs[vnfUUID].vfModules[vnfModuleUUID].version,
+ 'modelCustomizationId': serviceHierarchy.vnfs[vnfUUID].vfModules[vnfModuleUUID].customizationUuid,
+ 'modelCustomizationName': serviceHierarchy.vnfs[vnfUUID].vfModules[vnfModuleUUID].modelCustomizationName
+ },
+ 'instanceParams': [
+ {}
+ ]
+ };
+ }
+
+ generateVNFData(serviceHierarchy: any, vnfName: string, vnfUUID: string, formValues: any) {
+ return {
+ 'productFamilyId': formValues.productFamilyId,
+ 'lcpCloudRegionId': null,
+ 'tenantId': null,
+ 'lineOfBusiness': null,
+ 'platformName': null,
+ 'modelInfo': {
+ 'modelType': 'VF',
+ 'modelInvariantId': serviceHierarchy.vnfs[vnfName].invariantUuid,
+ 'modelVersionId': formValues.modelInfo.modelVersionId,
+ 'modelName': serviceHierarchy.vnfs[vnfName].name,
+ 'modelVersion': serviceHierarchy.vnfs[vnfName].version,
+ 'modelCustomizationId': serviceHierarchy.vnfs[vnfName].modelCustomizationId,
+ 'modelCustomizationName': serviceHierarchy.vnfs[vnfName].modelCustomizationName
+ },
+ 'isUserProvidedNaming': null
+ }
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/shared.module.ts b/vid-webpack-master/src/app/shared/shared.module.ts
new file mode 100644
index 000000000..ab6ecaa08
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/shared.module.ts
@@ -0,0 +1,92 @@
+import {NgModule, ModuleWithProviders} from '@angular/core';
+import {CommonModule} from '@angular/common';
+import {RouterModule} from '@angular/router';
+import { BrowserModule } from '@angular/platform-browser';
+import { HttpClientModule } from '@angular/common/http';
+import { ServiceInfoService } from './server/serviceInfo/serviceInfo.service';
+import { PopoverModule } from 'ngx-bootstrap';
+import { AngularSvgIconModule } from 'angular-svg-icon';
+import { SvgDirective } from './directives/svg/svg.directive';
+import { PopoverComponent } from './components/popover/popover.component';
+import { EllipsisComponent } from './components/ellipsis/ellipsis.component';
+import { MessageBoxComponent } from './components/messageBox/messageBox.component';
+import { MessageBoxService } from './components/messageBox/messageBox.service';
+import { SdcUiComponentsModule , SdcUiComponents} from 'sdc-ui/lib/angular';
+import { HttpInterceptorService } from './utils/httpInterceptor/httpInterceptor.service';
+import { FormControlErrorComponent } from './components/formControlError/formControlError.component';
+import { InputPreventionPatternDirective } from './directives/inputPrevention/inputPreventionPattern.directive';
+import { FormGeneralErrorsComponent } from './components/formGeneralErrors/formGeneralErrors.component';
+import { NumbersLettersUnderscoreValidator } from './components/validators/numbersLettersUnderscore/numbersLettersUnderscore.validator';
+import { SpinnerComponent } from './components/spinner/spinner.component';
+import { NoContentMessageAndIconComponent } from './components/no-content-message-and-icon/no-content-message-and-icon.component';
+import { ModelInformationComponent } from './components/model-information/model-information.component';
+import { TooltipModule } from 'ngx-tooltip';
+import {IframeService} from "./utils/iframe.service";
+import {CapitalizeAndFormatPipe} from "./pipes/capitalize/capitalize-and-format.pipe";
+import { DefaultDataGeneratorService } from './services/defaultDataServiceGenerator/default.data.generator.service';
+import {ServiceInfoPipe} from "./pipes/serviceInfo/serviceInfo.pipe";
+import {HealthStatusService} from "./server/healthStatusService/health-status.service";
+import {ConfigurationService} from "../services/configuration.service";
+import {FlagsResolve} from "../services/flags.resolve";
+
+
+@NgModule({
+ imports: [
+ BrowserModule,
+ HttpClientModule,
+ CommonModule,
+ RouterModule,
+ PopoverModule.forRoot(),
+ AngularSvgIconModule,
+ TooltipModule,
+ SdcUiComponentsModule,
+ ],
+ declarations: [
+ PopoverComponent,
+ SvgDirective,
+ EllipsisComponent,
+ MessageBoxComponent,
+ FormControlErrorComponent,
+ InputPreventionPatternDirective,
+ FormGeneralErrorsComponent,
+ SpinnerComponent,
+ NoContentMessageAndIconComponent,
+ ModelInformationComponent,
+ CapitalizeAndFormatPipe,
+ ServiceInfoPipe,
+ ],
+ exports: [
+ PopoverComponent,
+ SvgDirective,
+ EllipsisComponent,
+ MessageBoxComponent,
+ FormControlErrorComponent,
+ InputPreventionPatternDirective,
+ FormGeneralErrorsComponent,
+ SpinnerComponent,
+ NoContentMessageAndIconComponent,
+ ModelInformationComponent,
+ CapitalizeAndFormatPipe,
+ ServiceInfoPipe,
+ ],
+ providers: [
+ ServiceInfoService,
+ MessageBoxService,
+ SdcUiComponents.ModalService,
+ HttpInterceptorService,
+ IframeService,
+ NumbersLettersUnderscoreValidator,
+ DefaultDataGeneratorService,
+ HealthStatusService,
+ ConfigurationService,
+ FlagsResolve
+ ]
+})
+export class SharedModule {
+ static forRoot(): ModuleWithProviders {
+ return {
+ ngModule: SharedModule,
+ providers: [MessageBoxService]
+ };
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/utils/constants.ts b/vid-webpack-master/src/app/shared/utils/constants.ts
new file mode 100644
index 000000000..c78e12e28
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/utils/constants.ts
@@ -0,0 +1,287 @@
+export module Constants {
+
+ export class Component {
+ public static NAME = 'name';
+ public static SERVICE = 'service';
+ public static A_LA_CARTE = 'a la carte';
+ public static MACRO = 'Macro';
+ public static SUBSCRIBER_NAME = 'subscriberName';
+ public static OLDVERSION = 'oldversion';
+ public static SERVICE_TYPE = 'serviceType';
+ }
+
+ export class Path {
+ public static FORWARD_SLASH = '/';
+
+ public static AAI_GET_FULL_SUBSCRIBERS = '../../aai_get_full_subscribers';
+ public static AAI_REFRESH_FULL_SUBSCRIBERS = 'aai_refresh_full_subscribers';
+ public static AAI_GET_SUBSCRIBERS = '../../aai_get_subscribers';
+
+ public static AAI_GET_TENTANTS = '../../aai_get_tenants';
+ public static AAI_REFRESH_SUBSCRIBERS = 'aai_refresh_subscribers';
+ public static AAI_SUB_DETAILS = 'aai_sub_details';
+ public static AAI_SUB_VIEWEDIT = '../../aai_sub_viewedit';
+
+ public static GET_WORKFLOW = 'change-management/get_vnf_workflow_relation';
+ public static GET_MSO_WORKFLOWS = 'change-management/mso';
+ public static GET_SCHEDULER_CHANGE_MANAGEMENTS = 'change-management/scheduler';
+ public static CANCEL_SCHEDULE_REQUEST = 'change-management/scheduler/schedules';
+ public static ASSIGN = '?r=';
+ public static AAI_GET_SERVICE_INSTANCE_PATH = 'aai_get_service_instance/';
+ public static AAI_GET_SERVICES = '../../aai_get_services';
+ public static AAI_GET_AIC_ZONES = '../../aai_get_aic_zones';
+ public static AAI_GET_AIC_ZONE_FOR_PNF = 'aai_get_aic_zone_for_pnf/@globalCustomerId/@serviceType/@serviceInstanceId';
+ public static AAI_GET_SERVICES_BY_TYPE = 'aai_get_models_by_service_type';
+ public static AAI_GET_TENANTS = '../../aai_get_tenants/';
+ public static AAI_SUB_DETAILS_PATH = '../../aai_sub_details/';
+ public static AAI_GET_VERSION_BY_INVARIANT_ID = 'aai_get_version_by_invariant_id/';
+ public static SEARCH_SERVICE_INSTANCES = 'search_service_instances';
+ public static AAI_GET_VNF_DATA_PATH = 'aai_get_vnf_data/';
+ public static AAI_GET_VNF_BY_CUSTOMERID_AND_SERVICETYPE = 'get_vnf_data_by_globalid_and_service_type/';
+ public static AAI_GET_SERVICES_BY_OWNING_ENTITY_ID = 'aai_get_services_by_owning_entity_id';
+ public static AAI_GET_VNF_INFO = 'aai_get_vnf_information';
+ public static AAI_GET_PNF_INSTANCE = 'aai_get_service_instance_pnfs';
+ public static AAI_GET_VNF_INSTANCES_LIST = 'aai_get_vnf_instances';
+ public static AAI_GET_PNF_INSTANCES_LIST = 'aai_get_pnf_instances';
+ public static AAI_GET_BY_URI = 'aai_get_by_uri/';
+ public static AAI_GET_CONFIGURATION = 'aai_get_configuration/';
+ public static AAI_GET_TEST_ENVIRONMENTS = 'get_operational_environments?operationalEnvironmentType=';
+ public static GET_CATEGORY_PARAMETERS = '../../category_parameter';
+ public static PARAMETER_STANDARDIZATION_FAMILY = 'PARAMETER_STANDARDIZATION';
+ public static TENANT_ISOLATION_FAMILY = 'TENANT_ISOLATION';
+ public static ASDC_GETMODEL_PATH = 'asdc/getModel/';
+ public static CREATE_INSTANCE_PATH = '/models/services/createInstance';
+ public static AAI_GET_PNF_BY_NAME = 'aai_get_pnfs/pnf/';
+
+ public static GET_SYSTEM_PROP_VNF_PROV_STATUS_PATH = 'get_system_prop_vnf_prov_status';
+ public static GET_USER_ID = 'getuserID';
+ public static INSTANTIATE_ROOT_PATH = '#/instantiate?subscriberId=';
+ public static INSTANTIATE_PATH = '/instantiate';
+ public static INVALID_STRING = '/INVALID_STRING/';
+ public static INVALID_STRING_MSO_CREATE_SVC_INSTANCE = 'INVALID_STRING_mso_create_svc_instance';
+ public static MSO = 'mso';
+ public static MSO_CREATE_NW_INSTANCE = 'mso_create_nw_instance';
+ public static MSO_CREATE_NW_INSTANCE_PATH = 'mso_create_nw_instance/';
+ public static MSO_CREATE_SVC_INSTANCE = 'mso_create_svc_instance';
+ public static MSO_CREATE_VNF_INSTANCE = '../../mso/mso_create_vnf_instance/';
+ public static MSO_DELETE_SVC_INSTANCE_PATH = 'mso_delete_svc_instance/';
+ public static MSO_ACTIVATE_INSTANCE = 'mso/mso_activate_service_instance/@serviceInstanceId';
+ public static MSO_DEACTIVATE_INSTANCE = 'mso/mso_deactivate_service_instance/@serviceInstanceId';
+ public static MSO_CREATE_REALATIONSHIP = 'mso_add_relationship';
+ public static MSO_REMOVE_RELATIONSHIP = 'mso_remove_relationship';
+ public static SELECTED_SERVICE_SUB_PATH = '#/instances/subdetails?';
+ public static SELECTED_SERVICE_INSTANCE_SUB_PATH = 'serviceInstanceIdentifier=';
+ public static SELECTED_SUBSCRIBER_SUB_PATH = 'subscriberId=';
+ public static OWNING_ENTITY_SUB_PATH = 'owningEntity=';
+ public static PROJECT_SUB_PATH = 'project=';
+ public static SERVICE_TYPE_LIST_PATH = '#/instances/serviceTypes?serviceTypeList=';
+ public static SERVICE_MODLES_INSTANCES_SUBSCRIBERS_PATH = 'serviceModels.htm#/instances/subscribers';
+ public static SERVICES_DIST_STATUS_PATH = '../../rest/models/services?distributionStatus=';
+ public static SERVICES_PATH = '../../rest/models/services/';
+ public static SERVICETYPE_SUB_PATH = '&serviceType=';
+ public static SERVICEINSTANCEID_SUB_PATH = '&serviceInstanceId=';
+ public static SERVICEMODELS_INSTANCES_SERVICES_PATH = 'serviceModels.htm#/instances/services';
+ public static SERVICEMODELS_MODELS_SERVICES_PATH = 'serviceModels.htm#/models/services';
+ public static SUBDETAILS_SELECTEDSUBSCRIBER = '#subdetails?selectedSubscriber=';
+ public static SUBSCRIBERNAME_SUB_PATH = '&subscriberName=';
+ public static WELCOME_PATH = 'welcome.htm';
+ public static IS_PERMITTED_SUB_PATH = '&isPermitted=';
+ public static SERVICES_JOB_INFO_PATH = '../../asyncInstantiation';
+ public static CONFIGURATION_PATH = '../../get_property/{name}/defaultvalue';
+ public static SERVICES_JOB_AUDIT_PATH = '/auditStatus';
+ public static SERVICES_PROBE_PATH = "../../probe";
+ public static FEATURES_FLAG_PATH ="../../flags";
+
+ // Test Environment Urls =
+ public static OPERATIONAL_ENVIRONMENT_CREATE = 'operationalEnvironment/create';
+ public static OPERATIONAL_ENVIRONMENT_DEACTIVATE = 'operationalEnvironment/deactivate?operationalEnvironment=';
+ public static OPERATIONAL_ENVIRONMENT_ACTIVATE = 'operationalEnvironment/activate?operationalEnvironment=';
+ public static OPERATIONAL_ENVIRONMENT_STATUS = 'operationalEnvironment/requestStatus?requestId=';
+
+ }
+
+ export class Key {
+
+ public static DESCRIPTION = 'description';
+ public static GENERIC_VNF = 'generic-vnf';
+ public static GLOBAL_CUSTOMER_ID = 'global-customer-id';
+ public static GLOBAL_CUST_ID = 'globalCustomerId';
+ public static IN_MAINT = 'in-maint';
+ public static INVENTORY_RESPONSE_ITEMS = 'inventory-response-items';
+ public static INVENTORY_RESPONSE_ITEM = 'inventory-response-item';
+ public static L3_NETWORK = 'l3-network';
+ public static SUB_NET = 'subnet';
+ public static SUBNET_NAME = 'subnet-name';
+ public static SUBNET_ID = 'subnet-id';
+ public static GATEWAY_ADDRESS = 'gateway-address';
+ public static NETWORK_START_ADDRESS = 'network-start-address';
+ public static CIDR_MASK = 'cidr-mask';
+ public static MODEL_CUSTOMIZATION_ID = 'model-customization-id';
+ public static MODEL_INVAR_ID = 'model-invariant-id';
+ public static MODEL_VERSION_ID = 'model-version-id';
+ public static NETWORK_NAME = 'network-name';
+ public static NETWORK_ID = 'network-id';
+ public static NETWORK_TYPE = 'network-type';
+ public static NETWORKS = 'networks';
+ public static OPERATIONAL_STATUS = 'operational-status';
+ public static ORCHESTRATION_STATUS = 'orchestration-status';
+ public static PERCENT_PROGRESS = 'percent-progress';
+ public static PERSONA_MODEL_ID = 'persona-model-id';
+ public static PERSONA_MODEL_VERSION = 'persona-model-version';
+ public static PERSONA_MODEL_CUSTOMIZATION_ID = 'persona-model-customization-id';
+ public static PROV_STATUS = 'prov-status';
+
+ public static RESOURCE_LINK = 'resource-link';
+ public static RESULT_DATA = 'result-data';
+ public static SERVICE_DESCRIPTION = 'service-description';
+ public static SERVICE_ID = 'service-id';
+ public static SERVICE_INSTANCE = 'service-instance';
+ public static SERVICE_INSTANCES = 'service-instances';
+ public static SERVICE_INSTANCE_ID = 'service-instance-id';
+ public static SERVICE_INSTANCE_NAME = 'service-instance-name';
+ public static SERVICE_SUBSCRIPTION = 'service-subscription';
+ public static SERVICE_SUBSCRIPTIONS = 'service-subscriptions';
+ public static SERVICETYPE = 'service-type';
+ public static STATUS_MESSAGE = 'statusMessage';
+ public static SUBNAME = 'subscriber-name';
+ public static IS_PERMITTED = 'is-permitted';
+ public static TIMESTAMP = 'timestamp';
+ public static VF_MODULE = 'vf-module';
+ public static VF_MODULES = 'vfModules';
+ public static VF_MODULE_ID = 'vf-module-id';
+ public static VF_MODULE_NAME = 'vf-module-name';
+ public static VID = 'VID';
+ public static VNF_ID = 'vnf-id';
+ public static VNF_NAME = 'vnf-name';
+ public static VNF_TYPE = 'vnf-type';
+ public static VNFS = 'vnfs';
+ public static AVAILABLEVOLUMEGROUPS = 'availableVolumeGroups';
+ public static VOLUMEGROUPS = 'volumeGroups';
+ public static VOLUME_GROUP = 'volume-group';
+ public static VOLUME_GROUP_ID = 'volume-group-id';
+ public static VOLUME_GROUP_NAME = 'volume-group-name';
+ public static UPLOAD_SUPPLEMENTORY_DATA_FILE = 'uploadSupplementoryDataFile';
+ public static SUPPLEMENTORY_DATA_FILE = 'supplementoryDataFile';
+ public static ZONE_ID = 'zone-id';
+ public static ZONE_NAME = 'zone-name';
+ public static GENERIC_CONFIGURATION = 'configuration';
+ public static CONFIGURATIONS = 'configurations';
+ public static CONFIGURATION = 'configuration';
+ public static CONFIGURATION_NAME = 'configuration-name';
+ public static CONFIGURATION_TYPE = 'configuration-type';
+ public static CONFIGURATION_ID = 'configuration-id';
+ public static PORT = 'l-interface';
+ public static PORT_ID = 'interface-id';
+ public static PORT_NAME = 'interface-name';
+ public static PORT_MIRRORED = 'is-port-mirrored';
+ }
+
+ export class Status {
+ public static ALL = 'ALL';
+ public static COMPLETE = 'Complete';
+ public static DONE = 'Done';
+ public static ERROR = 'Error';
+ public static FAILED = 'Failed';
+ public static FAILED_SERVICE_MODELS_ASDC = 'Failed to get service models from SDC.';
+ public static FETCHING_SERVICE_TYPES = 'Fetching service types list from A&AI';
+ public static FETCHING_SERVICE_CATALOG = 'Fetching service catalog from AAI. Please wait.';
+ public static FETCHING_SERVICE_CATALOG_ASDC = 'Fetching service catalog from SDC. Please wait.';
+ public static FETCHING_SUB_DETAILS = 'Fetching subscriber details from A&AI for ';
+ public static FETCHING_SERVICE_INST_DATA = 'Fetching service instance data from A&AI for service-instance-id=';
+ public static FETCHING_SUBSCRIBER_LIST_AAI = 'Fetching subscriber list from A&AI...';
+ public static IN_PROGRESS = 'In Progress';
+ public static IS_SUCCESSFUL = ' isSuccessful = ';
+ public static MSO_FAILURE = 'msoFailure';
+ public static NONE = 'None';
+ public static NOT_FOUND = 'Not Found';
+ public static NO_SERVICE_SUBSCRIPTION_FOUND = 'No Service Subscription Found';
+ public static SUBMITTING_REQUEST = 'Submitting Request';
+ public static SUCCESS_VNF_PROV_STATUS = 'Successfully set the VNF\'s Prov_Status to ';
+ public static UNLOCKED = 'Unlocked';
+ public static AAI_ACTIVE = 'Active';
+ public static AAI_INACTIVE = 'Inactive';
+ public static AAI_CREATED = 'Created';
+ public static AAI_ENABLED = 'Enabled';
+ public static AAI_DISABLED = 'Disabled';
+ }
+
+ export class Error {
+ public static AAI = 'A&AI failure - see log below for details';
+ public static AAI_ERROR = 'A&AI Error';
+ public static AAI_FETCHING_CUST_DATA = 'Failed to fetch customer data from A&AI= Response Code= ';
+ public static FETCHING_SERVICE_TYPES = 'Failed to fetch service types from A&AI= Response Code= ';
+ public static FETCHING_SERVICES = 'Failed to fetch services from A&AI= Response Code= ';
+ public static FETCHING_SERVICE_INSTANCE_DATA = 'Failed to fetch service instance data from A&AI= Response Code= ';
+ public static INVALID_INSTANCE_NAME = 'Invalid instance name= ';
+ // tslint:disable-next-line:max-line-length
+ public static INSTANCE_NAME_VALIDATE = 'The instance name must contain only alphanumeric or \'_-.\' characters; and must start with an alphabetic character';
+ public static INVALID_LIST = 'Invalid list parameter= ';
+ public static INVALID_MAP = 'Invalid map parameter= ';
+ public static LIST_VALIDATE = 'A list parameter value must have the following syntax= \'[<value1>;\.\.\.;<valueN>]\'';
+ // tslint:disable-next-line:max-line-length
+ public static MAP_VALIDATE = 'A map parameter value must have the following syntax= \'{ <entry_key_1>= <entry_value_1>; \.\.\.; <entry_key_n>= <entry_value_n> }\'';
+ public static MAX_POLLS_EXCEEDED = 'Maximum number of poll attempts exceeded';
+ public static MISSING_DATA = 'Missing data';
+ public static MODEL_VERSION_ID_MISSING = 'Error= model-version-id is not populated in A&AI';
+ public static MSO = 'MSO failure - see log below for details';
+ public static NO_MATCHING_MODEL = 'No matching model found matching the persona Model Id = ';
+ public static NO_MATCHING_MODEL_AAI = 'No matching model found matching the A&AI model version ID = ';
+ public static SELECT = 'Please select a subscriber or enter a service instance';
+ public static SERVICE_INST_DNE = 'That service instance does not exist. Please try again.';
+ public static SYSTEM_FAILURE = 'System failure';
+ public static INVALID_DATA_FORMAT = 'Invalid data format.Please check your file content whether it is not in json or not.';
+ public static MISSING_FILE = 'Please Select JSON File.';
+
+ public static MISSING_VNF_DETAILS = 'Missing required information.\n' +
+ 'Please open and fill in the details.\n';
+ }
+
+ export class EventType {
+ public static COMPONENT_STATUS = 'ComponentStatus';
+ public static CREATE_COMPONENT = 'createComponent';
+ public static DELETE_RESUME_COMPONENT = 'deleteResumeComponent';
+ }
+
+ export class ServicePopup {
+ public static TITLE = 'Create a new service instance';
+ public static TOOLTIP_UUID = 'Unique identifier for this service in this version.';
+ public static TOOLTIP_INVARIANT_UUID = 'Unique identifier for this service cross versions.';
+
+ }
+
+ export class Parameter {
+ public static BOOLEAN = "boolean";
+ public static SELECT = "select";
+ public static MULTI_SELECT = "multi_select";
+ public static STRING = "string";
+ public static NUMBER = "number";
+ public static VALID_VALUES = "valid_values";
+ public static EQUAL = "equal";
+ public static LENGTH = "length";
+ public static MAX_LENGTH = "max_length";
+ public static MIN_LENGTH = "min_length";
+ public static IN_RANGE = "in_range";
+ public static CONSTRAINTS = "constraints";
+ public static OPERATOR = "operator";
+ public static CONSTRAINT_VALUES = "constraintValues";
+ public static DEFAULT = "default";
+ public static DESCRIPTION = "description";
+ public static TYPE = "type";
+ public static INTEGER = "integer";
+ public static RANGE = "range";
+ public static LIST = "list";
+ public static MAP = "map";
+ public static REQUIRED = "required";
+ public static GREATER_THAN = "greater_than";
+ public static LESS_THAN = "less_than";
+ public static GREATER_OR_EQUAL = "greater_or_equal";
+ public static LESS_OR_EQUAL = "less_or_equal";
+ public static DISPLAY_NAME = "displayName";
+ public static CHECKBOX ='checkbox';
+ public static FILE ='file';
+ }
+
+ export class AuditInfoModal{
+ public static TITLE = 'Service Instantiation Information';
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/utils/httpInterceptor/httpInterceptor.service.ts b/vid-webpack-master/src/app/shared/utils/httpInterceptor/httpInterceptor.service.ts
new file mode 100644
index 000000000..be9ade080
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/utils/httpInterceptor/httpInterceptor.service.ts
@@ -0,0 +1,32 @@
+import { Injectable } from '@angular/core';
+import {
+ HttpInterceptor,
+ HttpRequest,
+ HttpHandler,
+ HttpEvent, HttpErrorResponse
+} from '@angular/common/http';
+
+import { Observable } from 'rxjs/Observable';
+import { ErrorMessage, ErrorService } from '../../components/error/error.component.service';
+import { SpinnerComponent } from '../../components/spinner/spinner.component';
+
+@Injectable()
+export class HttpInterceptorService implements HttpInterceptor {
+ intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
+ SpinnerComponent.showSpinner.next(true);
+ return next.handle(request)
+ .catch((err: HttpErrorResponse) => {
+ if (err.status === 500) {
+ const errorMessage: ErrorMessage = new ErrorMessage('Server not available',
+ 'It appears that one of the backend servers is not responding.\n Please try later.',
+ 500);
+ ErrorService.showErrorWithMessage(errorMessage);
+ return Observable.of(null);
+ }
+ return Observable.throw(err);
+ }).finally(() => {
+ SpinnerComponent.showSpinner.next(false);
+ });
+ }
+}
+
diff --git a/vid-webpack-master/src/app/shared/utils/iframe.service.ts b/vid-webpack-master/src/app/shared/utils/iframe.service.ts
new file mode 100644
index 000000000..9a6636f4e
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/utils/iframe.service.ts
@@ -0,0 +1,19 @@
+import {Injectable} from "@angular/core";
+
+@Injectable()
+export class IframeService {
+
+ addClassOpenModal(elementClassName: string) {
+ var parentBodyElement = parent.document.getElementsByClassName(elementClassName)[0];
+ if (parentBodyElement) {
+ parentBodyElement.classList.add("modal-open");
+ }
+ }
+
+ removeClassCloseModal(elementClassName: string) {
+ var parentBodyElement = parent.document.getElementsByClassName(elementClassName)[0];
+ if (parentBodyElement) {
+ parentBodyElement.classList.remove("modal-open");
+ }
+ }
+}
diff --git a/vid-webpack-master/src/app/shared/utils/log/log.service.spec.ts b/vid-webpack-master/src/app/shared/utils/log/log.service.spec.ts
new file mode 100644
index 000000000..ea0eb0499
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/utils/log/log.service.spec.ts
@@ -0,0 +1,29 @@
+
+
+import {LogService} from "./log.service";
+
+describe('log service service', () => {
+ let logService : LogService;
+
+ beforeEach(() => {
+ logService = new LogService();
+ });
+
+
+ it('check all ILogger function are defined', ()=>{
+ expect(logService.log).toBeDefined();
+ expect(logService.assert).toBeDefined();
+ expect(logService.error).toBeDefined();
+ expect(logService.group).toBeDefined();
+ expect(logService.groupEnd).toBeDefined();
+ expect(logService.info).toBeDefined();
+ expect(logService.warn).toBeDefined();
+ });
+
+ it('test getPrefixLog function', ()=> {
+ let args = ['message', [1,2,3,4,5]];
+ let result = LogService.getPrefixLog(args);
+ expect(result).toBeDefined();
+ });
+
+});
diff --git a/vid-webpack-master/src/app/shared/utils/log/log.service.ts b/vid-webpack-master/src/app/shared/utils/log/log.service.ts
new file mode 100644
index 000000000..422fe0134
--- /dev/null
+++ b/vid-webpack-master/src/app/shared/utils/log/log.service.ts
@@ -0,0 +1,58 @@
+import {isDevMode} from "@angular/core";
+declare var console: any;
+
+export interface ILogger {
+ assert(...args: any[]): void;
+ error(...args: any[]): void;
+ group(...args: any[]): void;
+ groupEnd(...args: any[]): void;
+ info(...args: any[]): void;
+ log(...args: any[]): void;
+ warn(...args: any[]): void;
+}
+
+export class LogService implements ILogger {
+
+ isProduction : boolean = !isDevMode();
+ public assert(...args: any[]): void {
+ console.assert(LogService.getPrefixLog(...args));
+ }
+
+ public error(...args: any[]): void {
+ console.error(LogService.getPrefixLog(...args));
+ }
+
+ public group(...args: any[]): void {
+ console.group(LogService.getPrefixLog(...args));
+ }
+
+ public groupEnd(...args: any[]): void {
+ console.groupEnd(LogService.getPrefixLog(...args));
+ }
+
+ public info(...args: any[]): void {
+ console.info(LogService.getPrefixLog(...args));
+ }
+
+ public log(...args: any[]): void {
+ if(!this.isProduction){
+ console.log(LogService.getPrefixLog(...args));
+ }
+ }
+
+ public warn(...args: any[]): void {
+ console.warn(LogService.getPrefixLog(...args));
+ }
+
+ static getPrefixLog(...args :any[]){
+ return {
+ time : new Date(),
+ message : args[0],
+ data : args.length > 0 ? args[1] : ''
+ };
+ }
+}
+
+
+
+
diff --git a/vid-webpack-master/src/app/store/epics.ts b/vid-webpack-master/src/app/store/epics.ts
new file mode 100644
index 000000000..f424e7355
--- /dev/null
+++ b/vid-webpack-master/src/app/store/epics.ts
@@ -0,0 +1,13 @@
+import { Injectable } from '@angular/core';
+
+import {AAIEpics} from "../services/aaiService/aai.epics";
+
+@Injectable()
+export class RootEpics {
+ constructor(private aaiEpics: AAIEpics) {}
+
+ public createEpics() {
+ return this.aaiEpics.createEpic();
+
+ }
+}
diff --git a/vid-webpack-master/src/app/store/module.ts b/vid-webpack-master/src/app/store/module.ts
new file mode 100644
index 000000000..c0909c124
--- /dev/null
+++ b/vid-webpack-master/src/app/store/module.ts
@@ -0,0 +1,29 @@
+import { NgModule } from '@angular/core';
+import { NgReduxModule, NgRedux, DevToolsExtension } from '@angular-redux/store';
+import { RootEpics } from './epics';
+
+import rootReducer, {AppState} from "./reducers";
+import {AAIEpics} from "../services/aaiService/aai.epics";
+
+@NgModule({
+ imports: [NgReduxModule],
+ providers: [RootEpics, AAIEpics],
+})
+
+export class StoreModule {
+ constructor(
+ public store: NgRedux<AppState>,
+ devTools: DevToolsExtension,
+ rootEpics: RootEpics,
+ ) {
+
+ const persistedState = sessionStorage.getItem('reduxState') ?
+ JSON.parse(sessionStorage.getItem('reduxState')) : {};
+
+ store.configureStore(
+ rootReducer,
+ persistedState,
+ rootEpics.createEpics(),
+ devTools.isEnabled() ? [ devTools.enhancer() ] : []);
+ }
+}
diff --git a/vid-webpack-master/src/app/store/reducers.ts b/vid-webpack-master/src/app/store/reducers.ts
new file mode 100644
index 000000000..b3e4f4712
--- /dev/null
+++ b/vid-webpack-master/src/app/store/reducers.ts
@@ -0,0 +1,17 @@
+import {Reducer, combineReducers} from 'redux';
+import {GlobalReducer, GlobalState} from "../global.reducer";
+import {ServiceReducer, ServiceState} from "../service.reducer";
+
+
+export interface AppState {
+ global: GlobalState;
+ service: ServiceState;
+
+}
+
+const rootReducer: Reducer<AppState> = combineReducers<AppState>({
+ global: GlobalReducer,
+ service: ServiceReducer
+});
+
+export default rootReducer;
diff --git a/vid-webpack-master/src/app/utils/utils.ts b/vid-webpack-master/src/app/utils/utils.ts
new file mode 100644
index 000000000..dc4db3e4f
--- /dev/null
+++ b/vid-webpack-master/src/app/utils/utils.ts
@@ -0,0 +1,271 @@
+import { Constants } from '../shared/utils/constants';
+import Parameter = Constants.Parameter;
+import * as _ from 'lodash'
+
+export class Utils {
+
+ public static clampNumber = (number, min, max) => {
+ return Math.max(min, Math.min(number, max));
+ };
+
+ public static hasContents(object: Object): boolean {
+ if (object === undefined || object === null || object === "") {
+ return false;
+ }
+ return true;
+ };
+
+ public static convertModel(serviceModel) {
+
+ let isNewFlow:boolean = false;
+
+ for (let networkCustomizationName in serviceModel.networks) {
+ let networkModel = serviceModel.networks[networkCustomizationName];
+ if ( networkModel.customizationUuid != null ) {
+ isNewFlow = true;
+ break;
+ }
+ }
+ if ( !isNewFlow ) {
+ for (let vnfCustomizationName in serviceModel.vnfs) {
+ let vnfModel = serviceModel.vnfs[vnfCustomizationName];
+ if ( vnfModel.customizationUuid != null ) {
+ isNewFlow = true;
+ break;
+ }
+ }
+ }
+ if ( isNewFlow ) {
+ return (Utils.convertNewModel (serviceModel) );
+ }
+ else {
+ return (Utils.convertOldModel (serviceModel) );
+ }
+ };
+
+ private static convertNewModel (serviceModel ) {
+ let completeResources = new Array();
+ let resource = {};
+ let convertedAsdcModel = {
+ "service": serviceModel.service,
+ "networks": {},
+ "vnfs": {},
+ "pnfs": serviceModel.pnfs,
+ "serviceProxies": serviceModel.serviceProxies,
+ "completeDisplayInputs": {},
+ "isNewFlow": true
+ };
+
+ for(let key in serviceModel.service.inputs) {
+ if(_.includes(["instance_node_target", "naming_policy", "vf_instance_name"], key)) {
+ delete convertedAsdcModel.service.inputs[key];
+ }
+ }
+
+ for (let networkCustomizationName in serviceModel.networks) {
+ let networkModel = serviceModel.networks[networkCustomizationName];
+
+ convertedAsdcModel.networks[networkModel.customizationUuid] = {
+ "uuid": networkModel.uuid,
+ "invariantUuid": networkModel.invariantUuid,
+ "version": networkModel.version,
+ "name": networkModel.name,
+ "modelCustomizationName": networkModel.modelCustomizationName,
+ "customizationUuid": networkModel.customizationUuid,
+ "inputs": "",
+ "description": networkModel.description,
+ "commands": {},
+ "displayInputs": {}
+ };
+
+ resource = {
+ "name": networkModel.modelCustomizationName,
+ "description": networkModel.description
+ };
+
+ completeResources.push (resource);
+
+ }
+
+ _.forEach(serviceModel.configurations, function(element) {
+ element.isConfig = true;
+ });
+ _.forEach(serviceModel.pnfs, function(element, key) {
+ element.isPnf= true;
+ element.modelCustomizationName= key;
+ });
+ let mergedVnfs = Object.assign(serviceModel.vnfs, serviceModel.configurations, serviceModel.pnfs);
+
+ for (let vnfCustomizationName in mergedVnfs) {
+ let vnfModel = mergedVnfs[vnfCustomizationName];
+ let vnfCustomizationUuid = vnfModel.customizationUuid;
+ convertedAsdcModel.vnfs[vnfModel.customizationUuid] = {
+ "uuid": vnfModel.uuid,
+ "invariantUuid": vnfModel.invariantUuid,
+ "version": vnfModel.version,
+ "name": vnfModel.name,
+ "modelCustomizationName": vnfModel.modelCustomizationName,
+ "customizationUuid": vnfModel.customizationUuid,
+ "inputs": "",
+ "description": vnfModel.description,
+ "vfModules": {},
+ "volumeGroups": {},
+ "commands": {},
+ "displayInputs": {},
+ "properties": {},
+ "nfRole": "",
+ "nfType": "",
+ "sourceNodes": vnfModel.sourceNodes,
+ "collectorNodes": vnfModel.collectorNodes,
+ "isConfigurationByPolicy": vnfModel.configurationByPolicy ? vnfModel.configurationByPolicy : false,
+ "isConfig": vnfModel.isConfig ? vnfModel.isConfig : false,
+ "isPnf": vnfModel.isPnf ? vnfModel.isPnf : false
+ };
+
+ resource = {
+ "name": vnfModel.modelCustomizationName,
+ "description": vnfModel.description
+ };
+ completeResources.push (resource);
+
+ if (vnfModel.commands != null) {
+ /*
+ * commands: {
+ * internal_net_param_ntu: {
+ * command: get_input,
+ * displaName: internal_net_param_ntu,
+ * inputName: vccfd1_internal_net_param_ntu // pointer to input key
+ * }
+ * If the input name (ptr) is one of instance_node_target, naming_policy or vf_instance_name
+ * then ignore it
+ *
+ */
+
+ convertedAsdcModel.vnfs[vnfCustomizationUuid].properties=vnfModel.properties;
+ //
+ let vnf_type = "";
+ let vnf_role = "";
+ let vnf_function = "";
+ let vnf_code = "";
+ if ( !( _.isEmpty(vnfModel.properties) ) ) {
+ if (this.hasContents (vnfModel.properties.nf_type) ) {
+ vnf_type = vnfModel.properties.nf_type;
+ }
+ if (this.hasContents (vnfModel.properties.nf_role) ) {
+ vnf_role = vnfModel.properties.nf_role;
+ }
+ if (this.hasContents (vnfModel.properties.nf_function) ) {
+ vnf_function = vnfModel.properties.nf_function;
+ }
+ if (this.hasContents (vnfModel.properties.nf_naming_code) ) {
+ vnf_code = vnfModel.properties.nf_naming_code;
+ }
+ }
+ convertedAsdcModel.vnfs[vnfCustomizationUuid]["nfType"] = vnf_type;
+ convertedAsdcModel.vnfs[vnfCustomizationUuid]["nfRole"] = vnf_role;
+ convertedAsdcModel.vnfs[vnfCustomizationUuid]["nfFunction"] = vnf_function;
+ convertedAsdcModel.vnfs[vnfCustomizationUuid]["nfCode"] = vnf_code;
+ //
+ for (let vfModuleCustomizationName in serviceModel.vnfs[vnfCustomizationName].vfModules) {
+ let vfModuleModel = serviceModel.vnfs[vnfCustomizationName].vfModules[vfModuleCustomizationName];
+ convertedAsdcModel.vnfs[vnfCustomizationUuid].vfModules[vfModuleModel.customizationUuid] = vfModuleModel;
+ }
+
+ for (let volumeGroupCustomizationName in serviceModel.vnfs[vnfCustomizationName].volumeGroups) {
+ let volumeGroupModel = serviceModel.vnfs[vnfCustomizationName].volumeGroups[volumeGroupCustomizationName];
+ convertedAsdcModel.vnfs[vnfCustomizationUuid].volumeGroups[volumeGroupModel.customizationUuid] = volumeGroupModel;
+ }
+ }
+ }
+
+ return (convertedAsdcModel);
+ };
+
+ private static convertOldModel(serviceModel ) {
+ let resource = {};
+ let convertedAsdcModel = {
+ "service": serviceModel.service,
+ "networks": {},
+ "vnfs": {},
+ "pnfs": serviceModel.pnfs,
+ "serviceProxies": serviceModel.serviceProxies,
+ "completeDisplayInputs": {},
+ "isNewFlow": false
+ };
+ let completeResources = new Array();
+ for (let networkCustomizationName in serviceModel.networks) {
+ let networkModel = serviceModel.networks[networkCustomizationName];
+ convertedAsdcModel.networks[networkModel.invariantUuid] = {};
+ //convertedAsdcModel.networks[networkModel.invariantUuid][networkModel.version] = networkModel;
+ // need a network model to test this
+ convertedAsdcModel.networks[networkModel.uuid] = {
+ "uuid": networkModel.uuid,
+ "invariantUuid": networkModel.invariantUuid,
+ "version": networkModel.version,
+ "name": networkModel.name,
+ "modelCustomizationName": networkModel.modelCustomizationName,
+ "customizationUuid": networkModel.customizationUuid,
+ "inputs": "",
+ "description": networkModel.description,
+ "commands": {},
+ "displayInputs": {}
+ };
+ resource = {
+ "name": networkModel.modelCustomizationName,
+ "description": networkModel.description
+ };
+ completeResources.push (resource);
+ }
+
+ _.forEach(serviceModel.configurations, function(element) {
+ element.isConfig = true;
+ });
+ _.forEach(serviceModel.pnfs, function(element, key) {
+ element.isPnf= true;
+ element.modelCustomizationName= key;
+ });
+ let mergedVnfs = Object.assign(serviceModel.vnfs, serviceModel.configurations, serviceModel.pnfs);
+
+ for (let vnfCustomizationName in mergedVnfs) {
+ let vnfModel = mergedVnfs[vnfCustomizationName];
+ convertedAsdcModel.vnfs[vnfModel.uuid] = {
+ "uuid": vnfModel.uuid,
+ "invariantUuid": vnfModel.invariantUuid,
+ "version": vnfModel.version,
+ "name": vnfModel.name,
+ "modelCustomizationName": vnfModel.modelCustomizationName,
+ "customizationUuid": vnfModel.customizationUuid,
+ "inputs": "",
+ "description": vnfModel.description,
+ "vfModules": {},
+ "volumeGroups": {},
+ "commands": {},
+ "displayInputs": {},
+ "sourceNodes": vnfModel.sourceNodes,
+ "collectorNodes": vnfModel.collectorNodes,
+ "isConfigurationByPolicy": vnfModel.configurationByPolicy ? vnfModel.configurationByPolicy : false,
+ "isConfig": vnfModel.isConfig ? vnfModel.isConfig : false,
+ "isPnf": vnfModel.isPnf ? vnfModel.isPnf : false
+ };
+ resource = {
+ "name": vnfModel.modelCustomizationName,
+ "description": vnfModel.description
+ };
+ completeResources.push (resource);
+
+ for (let vfModuleCustomizationName in serviceModel.vnfs[vnfCustomizationName].vfModules) {
+ let vfModuleModel = serviceModel.vnfs[vnfCustomizationName].vfModules[vfModuleCustomizationName];
+ convertedAsdcModel.vnfs[vnfModel.uuid].vfModules[vfModuleModel.uuid] = vfModuleModel;
+ }
+
+ for (let volumeGroupCustomizationName in serviceModel.vnfs[vnfCustomizationName].volumeGroups) {
+ let volumeGroupModel = serviceModel.vnfs[vnfCustomizationName].volumeGroups[volumeGroupCustomizationName];
+ convertedAsdcModel.vnfs[vnfModel.uuid].volumeGroups[volumeGroupModel.uuid] = volumeGroupModel;
+ }
+ }
+
+ let completeDisplayInputs = {};
+
+ return (convertedAsdcModel);
+ };
+}
diff --git a/vid-webpack-master/src/app/vlanTagging/network-selector/network-selector.component.html b/vid-webpack-master/src/app/vlanTagging/network-selector/network-selector.component.html
new file mode 100644
index 000000000..fbb16949a
--- /dev/null
+++ b/vid-webpack-master/src/app/vlanTagging/network-selector/network-selector.component.html
@@ -0,0 +1,14 @@
+<div class="form-wrapper">
+ <form #form="ngForm">
+ <div class="network" *ngFor="let group of groups">
+ <label class="placeholder" [attr.data-tests-id]="'groupLabel'">{{getValueOfLabelInGroup(group,'Group Name')}}</label>
+ <select [(ngModel)]="groupSelection[getValueOfLabelInGroup(group,'Group Name')]" class="form-control input-text"
+ [attr.data-tests-id]="'groupTestId'"
+ id="{{getGroupName(group)}}" name="{{getGroupName(group)}}" required>
+ <option class="placeholder" [value]="undefined" disabled>Select Network</option>
+ <option *ngFor="let singleGroup of getNetworksByNetworkFunctionRole(group) | async"
+ [ngValue]="singleGroup">{{singleGroup["instance-group"]["instance-group-name"]}}</option>
+ </select>
+ </div>
+ </form>
+</div>
diff --git a/vid-webpack-master/src/app/vlanTagging/network-selector/network-selector.component.scss b/vid-webpack-master/src/app/vlanTagging/network-selector/network-selector.component.scss
new file mode 100644
index 000000000..aa45b34f3
--- /dev/null
+++ b/vid-webpack-master/src/app/vlanTagging/network-selector/network-selector.component.scss
@@ -0,0 +1,17 @@
+.form-wrapper{
+ width:640px;
+ padding-left: 50px;
+ padding-top: 50px;
+ .network{
+ padding-bottom: 30px;
+ }
+ .network {
+ select {
+ font-family: OpenSans-Italic;
+ font-size: 14px;
+ color: #959595 !important;
+ }
+ }
+}
+
+
diff --git a/vid-webpack-master/src/app/vlanTagging/network-selector/network-selector.component.ts b/vid-webpack-master/src/app/vlanTagging/network-selector/network-selector.component.ts
new file mode 100644
index 000000000..46a176984
--- /dev/null
+++ b/vid-webpack-master/src/app/vlanTagging/network-selector/network-selector.component.ts
@@ -0,0 +1,66 @@
+import {Component, Input, OnInit, ViewChild} from "@angular/core";
+import {NgRedux, select} from "@angular-redux/store";
+import {AppState} from "../../store/reducers";
+import {ModelInformationItem} from "../../shared/components/model-information/model-information.component";
+import {Observable} from "rxjs/Observable";
+import {NgForm} from "@angular/forms";
+import * as _ from 'lodash';
+
+@Component({
+ selector: "app-network-selector",
+ templateUrl: "./network-selector.component.html",
+ styleUrls: ["./network-selector.component.scss"]
+})
+export class NetworkSelectorComponent implements OnInit {
+ private localStore: NgRedux<AppState>;
+ networkSelection: any;
+ groupSelection :any;
+ @Input() groups: Array<string>;
+ @Input() cloudOwner : string;
+ @Input() cloudRegionId : string;
+ @select(['service', 'networkFunctions'])
+ readonly networkFunctions: Observable<any>;
+
+ @ViewChild('form') form: NgForm;
+
+ constructor(store: NgRedux<AppState>) {
+ this.localStore = store;
+ this.groupSelection = {};
+ console.log(store);
+ }
+
+ getValueOfLabelInGroup(group: any, label: string){
+ let item = _.find(group, {"label": label});
+ if (item) {
+ return item["values"][0];
+ }
+ }
+
+ getNetworksByNetworkFunctionRole(group: any): Observable<string[]> {
+ let filteredItem = this.getValueOfLabelInGroup(group,"Network Collection Function");
+ return this.networkFunctions.map(data => {
+ return (data && data[filteredItem]) || [];
+ });
+ }
+
+ getGroupName(group: ModelInformationItem[]) {
+ return this.getValueOfLabelInGroup(group,"Group Name");
+ }
+
+ /**
+ * [ncf=>aaiResonse]
+ * groups => groupsModel
+ */
+
+ ngOnInit() {
+ let store = this.localStore;
+ this.networkSelection = {};
+
+ }
+}
+
+
+//
+/*
+Info inside redux = {ncfNetworkMap }
+*/
diff --git a/vid-webpack-master/src/app/vlanTagging/vlan-tagging.component.html b/vid-webpack-master/src/app/vlanTagging/vlan-tagging.component.html
new file mode 100644
index 000000000..f474f4bd1
--- /dev/null
+++ b/vid-webpack-master/src/app/vlanTagging/vlan-tagging.component.html
@@ -0,0 +1,27 @@
+<div class="vlan-wrapper-config">
+ <div class="head">
+ <div class="title">Collection Resource Consumer VNF</div>
+ <div class="btn-wrapper">
+ <button class="cancel-btn grey" data-tests-id="cancelButton" (click)="cancel()">{{cancelButtonText}}</button>
+ <button class="next-btn blue" data-tests-id="nextButton" [disabled]="isNextButtonDisabled()" (click)="nextStep()">{{nextButtonText}}</button>
+ </div>
+ </div>
+ <span (serviceInstamce)="onServiceInstanceChange($event)"></span>
+ <div class="content-wrapper">
+ <div class="left-side">
+ <formasync [hidden]="currentStep === wizardSteps.two" [model]="model" class="form"></formasync>
+ <app-network-selector [hidden]="currentStep === wizardSteps.one" class="form-wrapper" [groups]="groups"></app-network-selector>
+ </div>
+
+ <div style="padding-left: 30px;padding-right: 30px" class="sidebar-right">
+ <div class="headline">META DATA</div>
+ <div class="seperator"></div>
+ <model-information [modelInformationItems]="modelInfoItems"></model-information>
+ <div class="headline">Collection Resource Consumer VNF</div>
+ <div *ngFor="let group of groups">
+ <div class="seperator"></div>
+ <model-information [modelInformationItems]="group"></model-information>
+ </div>
+ </div>
+ </div>
+</div>
diff --git a/vid-webpack-master/src/app/vlanTagging/vlan-tagging.component.scss b/vid-webpack-master/src/app/vlanTagging/vlan-tagging.component.scss
new file mode 100644
index 000000000..af4a7e212
--- /dev/null
+++ b/vid-webpack-master/src/app/vlanTagging/vlan-tagging.component.scss
@@ -0,0 +1,168 @@
+$popupHeaderHeight: 59px;
+
+.vlan-wrapper-config * {
+ font-family: OpenSans-Regular, sans-serif;
+}
+
+.body-content-jsp {
+ margin-top: 35px;
+ margin-left: 201px;
+ margin-right: 0px;
+ background-color: white;
+}
+
+:host {
+ height: 100%;
+}
+.form-wrapper{
+ min-width: 75%;
+ overflow: auto;
+}
+button {
+ border-radius: 2px;
+ font-size: 14px;
+ line-height: 28px;
+ height: 30px;
+ &.blue {
+ border: #0091c8 1px solid;
+ background-color: #009fdb;
+ color: white;
+ &:hover {
+ background-color: #1ec2ff;
+ border-color: #0091c8;
+ }
+ &:active {
+ background-color: #0091c7;
+ border-color: #006186;
+ }
+ &[disabled] {
+ background-color: rgba(5, 104, 174, 0.3);
+ border-color: rgba(4, 113, 168, 0.3);
+ }
+ }
+ &.grey {
+ color: #009FDB;
+ background-color: #ffffff;
+ border: 1px solid #009FDB;
+ &:hover {
+ background-color: #f8f8f8;
+ border-color: #009fdb;
+ }
+ &:active {
+ background-color: #d8d8d8;
+ border-color: #5a5a5a;
+ }
+ &[disabled] {
+ background-color: #f8f8f8;
+ border-color: #d8d8d8;
+ color: #cdcdcd;
+ }
+ }
+ &.white {
+ border: #009fdb 1px solid;
+ background-color: white;
+ color: #009fdb;
+ }
+}
+
+.vlan-wrapper-config {
+ /*todo: remove. this a temporary fix for the sub-interface popup not showing as a page beside the sidebar. currently showing it in full screen.*/
+ /*it is necessary inside the iframe (and not just in the angularjs - old app) angular app because in Firefox the iframe content isn't effected by the iframe size */
+ width: 100vw;
+ height: 100vh;
+ position: fixed;
+ /********************/
+ .head {
+ line-height: $popupHeaderHeight;
+ height: $popupHeaderHeight;
+ display: flex;
+ background-color: #F8F8F8;
+ border-bottom: 1px solid #D8D8D8;
+ .title {
+ font-size: 18px;
+ margin-left: 56px;
+ color: #5A5A5A;
+ }
+ .btn-wrapper {
+ flex: 1;
+ text-align: right;
+ margin-right: 15px;
+ button {
+ width: 120px;
+ &.delete-btn {
+ margin-left: 13px;
+ }
+ }
+ }
+ }
+ .content-wrapper {
+ display: flex;
+ .form {
+ overflow-y: auto;
+ }
+ height: calc(100% - #{$popupHeaderHeight});
+ .form {
+ margin-top: 48px;
+
+ }
+ .content {
+ .form-wrapper {
+
+ margin: 0 auto;
+ }
+ }
+
+ }
+
+ span.error {
+ color: #cf2a2a;
+ }
+ .content-wrapper .content .form-wrapper .instance-field {
+ .ng-invalid-pattern {
+ border-color: #cf2a2a;
+ color: #cf2a2a;
+ }
+ margin-bottom: 25px;
+ label {
+ color: #191919;
+ font-size: 13px;
+ }
+ input,
+ select {
+ border-color: #D2D2D2;
+ }
+ &.lcpRegionText,
+ &.productFamily {
+ display: none;
+ }
+ }
+
+}
+
+.sidebar-right {
+ min-width: 25%;
+ background-color: #F8F8F8;
+ overflow-y: auto;
+ .headline {
+ font-family: OpenSans-Semibold;
+ font-size: 12px;
+ color: #009FDB;
+ padding-bottom: 6px;
+ padding-top: 20px
+ }
+ .seperator{
+ background: #D2D2D2;
+ height: 1px;
+ margin-bottom: 10px;
+ }
+}
+
+.left-side{
+ min-width: 75%;
+ overflow:auto;
+
+}
+
+.sidebar-right service-metadata .metadata-content {
+ padding-bottom: 20px;
+}
diff --git a/vid-webpack-master/src/app/vlanTagging/vlan-tagging.component.ts b/vid-webpack-master/src/app/vlanTagging/vlan-tagging.component.ts
new file mode 100644
index 000000000..f3f63e1e9
--- /dev/null
+++ b/vid-webpack-master/src/app/vlanTagging/vlan-tagging.component.ts
@@ -0,0 +1,203 @@
+import {formasync} from './../components/form-async/form-async.component';
+import {Component, OnInit, ViewChild} from "@angular/core";
+import {NetworkSelectorComponent} from "./network-selector/network-selector.component";
+import {NgRedux, select} from "@angular-redux/store";
+import {AppState} from "../store/reducers";
+import {ActivatedRoute} from "@angular/router";
+import {
+ loadServiceAccordingToUuid, loadAaiNetworkAccordingToNetworkCF,
+ loadUserId
+} from "../services/aaiService/aai.actions";
+import {createRequest} from "../factories/mso.factory";
+import {Observable} from "rxjs/Observable";
+import {VNFModel} from "../shared/models/vnfModel";
+import {VfcInstanceGroupProperties} from "../shared/models/vfcInstanceGroupProperties";
+import * as _ from "lodash";
+import {ModelInformationItem} from "../shared/components/model-information/model-information.component";
+
+enum WizardSteps {
+ one,
+ two
+}
+
+const buttonTextNext = "Next";
+const buttonTextBack = "Back";
+const buttonTextConfirm = "Confirm";
+const buttonTextCancel = "Cancel";
+
+@Component({
+ selector: "vlan-tagging",
+ templateUrl: "./vlan-tagging.component.html",
+ styleUrls: ["./vlan-tagging.component.scss"]
+})
+
+export class VlanTaggingComponent implements OnInit {
+ constructor(private store: NgRedux<AppState>,
+ private route: ActivatedRoute) {
+ this.nextButtonText = buttonTextNext;
+ this.cancelButtonText = buttonTextCancel;
+ this.currentStep = WizardSteps.one;
+ }
+
+ subscriberName: string;
+ serviceKey: string;
+ serviceType: string;
+ vnfKey: string;
+ serviceInstanceName: string;
+ serviceModelId: string;
+ modelInfoItems: Array<ModelInformationItem>;
+ groups: Array<Array<ModelInformationItem>>;
+ currentStep: WizardSteps;
+ nextButtonText: string;
+ cancelButtonText: string;
+ wizardSteps = WizardSteps;
+ cloudOwner: string;
+ cloudRegionId: string;
+ serviceInstanceId : string;
+ model: VNFModel;
+ userId: string;
+ modelCustomizationId : string;
+ onServiceInstanceChange(event) {
+ console.log(event);
+ }
+
+ private serviceHirarchy: any;
+
+ @select(['service', 'serviceHierarchy'])
+ readonly serviceHierarchyObserable: Observable<any>;
+
+ @select(['service', 'userId'])
+ readonly userIdObs: Observable<any>;
+
+
+ @ViewChild(NetworkSelectorComponent)
+ public networkSelectorComponent: NetworkSelectorComponent;
+ @ViewChild(formasync)
+ public formAsync: formasync;
+
+
+ deploySubInterface() {
+
+ const requestDetails = createRequest(
+ this.userId,
+ this.formAsync.serviceInstance,
+ this.serviceHirarchy[this.serviceModelId],
+ this.serviceKey,
+ this.networkSelectorComponent.groupSelection,
+ this.vnfKey,
+ this.modelCustomizationId
+ );
+
+ // this.msoService.createVnf(requestDetails, this.serviceKey).subscribe();
+
+ window.parent.postMessage({
+ eventId: 'submitIframe',
+ data: requestDetails
+ }, "*");
+ }
+
+ ngOnInit() {
+ this.cloudRegionId = "";
+ this.store.dispatch(loadUserId());
+ this.userIdObs.subscribe(res => this.userId = res);
+ this.route.queryParams.subscribe(params => {
+ this.serviceModelId = params["serviceModelId"];
+ this.subscriberName = params["subscriberName"];
+ this.serviceType = params["serviceType"];
+ this.serviceKey = params["serviceInstanceID"];
+ this.vnfKey = params["modelCustomizationName"];
+ this.serviceInstanceId = params["serviceInstanceID"];
+ this.serviceInstanceName = params["serviceInstanceName"];
+ this.modelCustomizationId = params["modelCustomizationId"];
+ this.cloudOwner = params["globalCustomerId"];
+ this.store.dispatch(loadServiceAccordingToUuid(this.serviceModelId));
+ this.serviceHierarchyObserable.subscribe(data => {
+ this.serviceHirarchy = data;
+ if (data && data[this.serviceModelId]) {
+ this.model = new VNFModel(data[this.serviceModelId].vnfs[this.vnfKey]);
+ this.updateModelInfo(this.model);
+ }
+ });
+ });
+ }
+
+ private updateModelInfo(vnfModel: VNFModel) {
+ this.modelInfoItems = [
+ new ModelInformationItem("Service Instance Name", "serviceInstanceName", [this.serviceInstanceName], "", true),
+ new ModelInformationItem("Model Invariant UUID", "modelInvariantUUID", [vnfModel.invariantUuid], "", true),
+ new ModelInformationItem("Model Version", "modelVersion", [vnfModel.version], "", true),
+ new ModelInformationItem("Model UUID", "modelUuid", [vnfModel.uuid], "", true),
+ new ModelInformationItem("Model Customization UUID", "modelCustomizationUuid", [vnfModel.customizationUuid], "", true),
+ ];
+
+ this.groups = [];
+ _.forOwn(vnfModel.vfcInstanceGroups, (vfcInstanceGroup, key) => {
+ const properties: VfcInstanceGroupProperties = vfcInstanceGroup.vfcInstanceGroupProperties;
+ this.groups.push(this.createGroupsInformation(vfcInstanceGroup.name, properties));
+ });
+ }
+
+ nextStep() {
+ switch (this.currentStep) {
+ case WizardSteps.one:
+ this.groups.map(group => {
+ let networkName = _.find(group, (groupElements: ModelInformationItem) => groupElements.testsId === "networkCollectionFunction");
+ this.store.dispatch(
+ loadAaiNetworkAccordingToNetworkCF(networkName["values"][0], this.cloudOwner, this.formAsync.serviceInstance.lcpRegion)
+ );
+ });
+ this.currentStep = WizardSteps.two;
+ this.updateNavigationButtonText(this.currentStep);
+ break;
+ case WizardSteps.two:
+ this.deploySubInterface();
+ break;
+ }
+ }
+
+ cancel() {
+ switch (this.currentStep) {
+ case WizardSteps.one:
+ window.parent.postMessage({
+ eventId: 'closeIframe'
+ }, "*");
+ break;
+ case WizardSteps.two:
+ this.currentStep = WizardSteps.one;
+ this.updateNavigationButtonText(this.currentStep);
+ break;
+ }
+ }
+
+ updateNavigationButtonText(step: WizardSteps) {
+ switch (step) {
+ case WizardSteps.one:
+ this.nextButtonText = buttonTextNext;
+ this.cancelButtonText = buttonTextCancel;
+ break;
+ case WizardSteps.two:
+ this.nextButtonText = buttonTextConfirm;
+ this.cancelButtonText = buttonTextBack;
+ break;
+ }
+ }
+
+ isNextButtonDisabled() {
+ switch (this.currentStep) {
+ case WizardSteps.one:
+ return !this.formAsync.form.valid;
+ case WizardSteps.two:
+ return !this.networkSelectorComponent.form.valid;
+ }
+ }
+
+ createGroupsInformation(name: string, properties: VfcInstanceGroupProperties): Array<ModelInformationItem> {
+ let modelInfoItems = [];
+ modelInfoItems.push(new ModelInformationItem("Group Name", "groupName", [name], "", true));
+ modelInfoItems.push(new ModelInformationItem("Network Collection Function", "networkCollectionFunction", [properties.networkCollectionFunction], "", true));
+ modelInfoItems.push(new ModelInformationItem("VFC Instance Group Function", "instanceGroupFunction", [properties.vfcInstanceGroupFunction], "", true));
+ modelInfoItems.push(new ModelInformationItem("Parent Port Role", "parentPortRole", [properties.vfcParentPortRole], "", true));
+ modelInfoItems.push(new ModelInformationItem("Sub Interface Role", "subInterfaceRole", [properties.subinterfaceRole], "", true));
+ return modelInfoItems;
+ }
+}
diff --git a/vid-webpack-master/src/app/vlanTagging/vlan-tagging.module.ts b/vid-webpack-master/src/app/vlanTagging/vlan-tagging.module.ts
new file mode 100644
index 000000000..3227542c6
--- /dev/null
+++ b/vid-webpack-master/src/app/vlanTagging/vlan-tagging.module.ts
@@ -0,0 +1,33 @@
+
+import { formasync } from './../components/form-async/form-async.component';
+import {NgModule,} from '@angular/core';
+import { FormsModule } from '@angular/forms';
+import { VlanTaggingComponent } from './vlan-tagging.component';
+import {CommonModule} from '@angular/common';
+import { BrowserModule } from '@angular/platform-browser';
+import { NgReduxModule } from '@angular-redux/store';
+import { SharedModule } from '../shared/shared.module';
+import { NetworkSelectorComponent } from './network-selector/network-selector.component';
+import { TooltipModule } from 'ngx-tooltip';
+
+
+
+@NgModule({
+
+imports: [
+ CommonModule,
+ NgReduxModule,
+ FormsModule,
+ BrowserModule,
+ TooltipModule,
+ SharedModule.forRoot()
+
+ ],
+ providers: [ ],
+ declarations: [VlanTaggingComponent,formasync,NetworkSelectorComponent],
+ entryComponents: [],
+ exports: [formasync]
+
+})
+
+export class VlanTaggingModule { }